@atmos.build/ui 0.1.5 → 0.1.7

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.
@@ -7,7 +7,7 @@ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigge
7
7
  import { MiddleTruncate } from './middle-truncate.js';
8
8
  import { StickyHeaderFade } from './sticky-header-fade.js';
9
9
  export function DetailTopBar({ title, trail, meta, actions, className, contentClassName, leftClassName, actionsClassName, chromeFont, headingFont, dataTestId, fade = true, }) {
10
- return (_jsxs("div", { className: cn('bg-background/95 sticky top-0 z-50 flex h-10 items-center justify-between gap-3 px-3 backdrop-blur', chromeFont, className), "data-slot": "detail-top-bar", "data-testid": dataTestId, children: [_jsxs("div", { className: cn('flex min-w-0 flex-1 items-center gap-3 overflow-hidden', contentClassName), children: [_jsx("div", { className: cn('flex min-w-0 flex-1 items-center overflow-hidden', leftClassName), children: trail ?? (_jsx("h1", { className: cn('text-foreground min-w-0 truncate text-[13px] leading-5 font-medium', headingFont), children: title })) }), meta ? (_jsx("div", { className: "text-muted-foreground min-w-0 shrink truncate font-mono text-[11.5px]", children: meta })) : null] }), actions ? (_jsx("div", { className: cn('flex shrink-0 items-center gap-1', actionsClassName), children: actions })) : null, fade ? _jsx(StickyHeaderFade, { "data-slot": "detail-top-bar-fade" }) : null] }));
10
+ return (_jsxs("div", { className: cn('bg-background/95 sticky top-0 z-50 flex h-10 items-center justify-between gap-3 px-4 backdrop-blur', chromeFont, className), "data-slot": "detail-top-bar", "data-testid": dataTestId, children: [_jsxs("div", { className: cn('flex min-w-0 flex-1 items-center gap-3 overflow-hidden', contentClassName), children: [_jsx("div", { className: cn('flex min-w-0 flex-1 items-center overflow-hidden', leftClassName), children: trail ?? (_jsx("h1", { className: cn('text-foreground min-w-0 truncate text-[13px] leading-5 font-medium', headingFont), children: title })) }), meta ? (_jsx("div", { className: "text-muted-foreground min-w-0 shrink truncate font-mono text-[11.5px]", children: meta })) : null] }), actions ? (_jsx("div", { className: cn('flex shrink-0 items-center gap-1', actionsClassName), children: actions })) : null, fade ? _jsx(StickyHeaderFade, { "data-slot": "detail-top-bar-fade" }) : null] }));
11
11
  }
12
12
  export function DetailBreadcrumb({ items, ariaLabel, className, separator = '/', collapseMiddle = false, tailItems = 2, collapsedAriaLabel, dataTestId, }) {
13
13
  const collapsedItems = collapseMiddle ? collapsedMiddleItems(items, tailItems) : [];
@@ -6,6 +6,7 @@ export interface NautAppearance {
6
6
  shape: NautShape;
7
7
  color: NautColor;
8
8
  }
9
+ export type NautAnimationRate = 'efficient' | 'smooth';
9
10
  export interface NautAvatarProps extends Omit<React.SVGProps<SVGSVGElement>, 'ref'> {
10
11
  shape?: NautShape;
11
12
  color?: NautColor;
@@ -19,6 +20,7 @@ export interface NautAvatarProps extends Omit<React.SVGProps<SVGSVGElement>, 're
19
20
  } | null;
20
21
  /** Glance at a mouse that comes near the face. Ignored once `gaze` is given. */
21
22
  followPointer?: boolean;
23
+ animationRate?: NautAnimationRate;
22
24
  /** Any stable id — keeps a list of Nauts from blinking in unison. */
23
25
  seed?: string | number;
24
26
  }
@@ -10,6 +10,7 @@ export { NAUT_COLORS, NAUT_COLOR_KEYS, NAUT_EXPRESSIONS, NAUT_GESTURES, NAUT_SHA
10
10
  const RECT_MAX_AGE_MS = 500;
11
11
  const IDLE_FRAME_MS = 1000 / 3;
12
12
  const RESPONSIVE_FRAME_MS = 1000 / 20;
13
+ const SMOOTH_FRAME_MS = 1000 / 60;
13
14
  const POINTER_SETTLE_MS = 350;
14
15
  /** Where the mouse is, shared by every face so one listener serves the page. */
15
16
  const pointer = {
@@ -75,7 +76,11 @@ const ticker = {
75
76
  if (!entry.visible)
76
77
  continue;
77
78
  const responsive = (entry.follow && pointerResponsive) || entry.engine.needsResponsiveFrameRate;
78
- const frameMs = responsive ? RESPONSIVE_FRAME_MS : IDLE_FRAME_MS;
79
+ const frameMs = entry.smooth
80
+ ? SMOOTH_FRAME_MS
81
+ : responsive
82
+ ? RESPONSIVE_FRAME_MS
83
+ : IDLE_FRAME_MS;
79
84
  if (now - entry.lastUpdate < frameMs)
80
85
  continue;
81
86
  const dt = Math.min((now - entry.lastUpdate) / 1000, 0.1);
@@ -111,7 +116,7 @@ const seedNumber = (seed) => typeof seed === 'number' ? seed : hashSeed(seed ??
111
116
  * look around. The eyes are holes, so set `--naut-avatar-eye` to the surface the
112
117
  * avatar sits on (defaults to `--background`).
113
118
  */
114
- export const NautAvatar = React.forwardRef(function NautAvatar({ shape = 'circle', color = 'ink', expression = 'neutral', idle = true, gaze = null, followPointer = true, seed, className, style, ...props }, forwardedRef) {
119
+ export const NautAvatar = React.forwardRef(function NautAvatar({ shape = 'circle', color = 'ink', expression = 'neutral', idle = true, gaze = null, followPointer = true, animationRate = 'efficient', seed, className, style, ...props }, forwardedRef) {
115
120
  const reducedMotion = useReducedMotion();
116
121
  const animated = idle && !reducedMotion;
117
122
  const svgRef = React.useRef(null);
@@ -126,6 +131,7 @@ export const NautAvatar = React.forwardRef(function NautAvatar({ shape = 'circle
126
131
  svg: null,
127
132
  visible: true,
128
133
  follow: false,
134
+ smooth: false,
129
135
  rect: null,
130
136
  rectAt: -1,
131
137
  rectTime: 0,
@@ -141,7 +147,8 @@ export const NautAvatar = React.forwardRef(function NautAvatar({ shape = 'circle
141
147
  engine.idle = animated;
142
148
  engine.gazeTarget = gaze;
143
149
  entry.follow = followPointer && !gaze && animated;
144
- }, [engine, entry, shape, color, expression, animated, gaze, followPointer]);
150
+ entry.smooth = animationRate === 'smooth';
151
+ }, [engine, entry, shape, color, expression, animated, gaze, followPointer, animationRate]);
145
152
  React.useLayoutEffect(() => {
146
153
  if (!rootRef.current ||
147
154
  !bodyRef.current ||
@@ -191,5 +198,5 @@ export const NautAvatar = React.forwardRef(function NautAvatar({ shape = 'circle
191
198
  engine.settle();
192
199
  engine.update(0);
193
200
  }, [animated, engine, shape, color, expression]);
194
- return (_jsx("svg", { ref: svgRef, viewBox: NAUT_VIEWBOX, "data-slot": "naut-avatar", "data-shape": shape, "data-color": color, "data-expression": expression, "data-atmos-motion": animated ? 'running' : undefined, "data-atmos-motion-property": animated ? 'svg-attributes' : undefined, className: cn('block size-full overflow-visible select-none', className), style: style, "aria-hidden": props['aria-label'] ? undefined : true, ...props, children: _jsxs("g", { ref: rootRef, children: [_jsx("path", { ref: bodyRef }), _jsxs("g", { ref: eyesRef, children: [_jsx("path", { ref: eyeLRef, fill: "var(--naut-avatar-eye, var(--background))" }), _jsx("path", { ref: eyeRRef, fill: "var(--naut-avatar-eye, var(--background))" })] })] }) }));
201
+ return (_jsx("svg", { ref: svgRef, viewBox: NAUT_VIEWBOX, "data-slot": "naut-avatar", "data-shape": shape, "data-color": color, "data-expression": expression, "data-animation-rate": animationRate, "data-atmos-motion": animated ? 'running' : undefined, "data-atmos-motion-property": animated ? 'svg-attributes' : undefined, className: cn('block size-full overflow-visible select-none', className), style: style, "aria-hidden": props['aria-label'] ? undefined : true, ...props, children: _jsxs("g", { ref: rootRef, children: [_jsx("path", { ref: bodyRef }), _jsxs("g", { ref: eyesRef, children: [_jsx("path", { ref: eyeLRef, fill: "var(--naut-avatar-eye, var(--background))" }), _jsx("path", { ref: eyeRRef, fill: "var(--naut-avatar-eye, var(--background))" })] })] }) }));
195
202
  });
@@ -4,10 +4,7 @@ export interface SpecStripItem {
4
4
  label: string;
5
5
  value: React.ReactNode;
6
6
  suffix?: React.ReactNode;
7
- /**
8
- * What the value is changing from. Present, the item reads "before → after", which is what a
9
- * shape being upgraded is: the new number alone says what you get without saying what moved.
10
- */
7
+ /** What the value is changing from. Present, the item reads "before → after". (audited:keep - documents the rendered text contract) */
11
8
  from?: React.ReactNode;
12
9
  }
13
10
  export interface SpecStripProps extends Omit<React.ComponentProps<'div'>, 'children'> {
package/dist/index.d.ts CHANGED
@@ -68,7 +68,7 @@ export { PropertyPanel, type PropertyPanelProps, type PropertyPanelLabels, } fro
68
68
  export { SortableList, SortableItem, SortableRow, DragHandle, DragPreview, useSortableHandle, useSortableRow, reorderById, type SortableListProps, type ReorderDetail, type DragHandleProps, DndContext, KeyboardSensor, PointerSensor, SortableContext, arrayMove, closestCenter, sortableKeyboardCoordinates, useDraggable, useDroppable, useSensor, useSensors, verticalListSortingStrategy, type DragEndEvent, type DragOverEvent, type DragStartEvent, } from './components/sortable.js';
69
69
  export { VoiceLine, type VoiceLineProps, type VoiceLineState } from './components/voice-line.js';
70
70
  export { ShimmerText, type ShimmerTextProps } from './components/shimmer-text.js';
71
- export { NautAvatar, NAUT_COLORS, NAUT_COLOR_KEYS, NAUT_EXPRESSIONS, NAUT_GESTURES, NAUT_SHAPES, isNautColor, isNautShape, nautAppearanceForSeed, type NautAppearance, type NautAvatarHandle, type NautAvatarProps, type NautColor, type NautExpression, type NautGesture, type NautShape, } from './components/naut-avatar.js';
71
+ export { NautAvatar, NAUT_COLORS, NAUT_COLOR_KEYS, NAUT_EXPRESSIONS, NAUT_GESTURES, NAUT_SHAPES, isNautColor, isNautShape, nautAppearanceForSeed, type NautAnimationRate, type NautAppearance, type NautAvatarHandle, type NautAvatarProps, type NautColor, type NautExpression, type NautGesture, type NautShape, } from './components/naut-avatar.js';
72
72
  export { NautScene, NAUT_SCENES, type NautSceneDef, type NautSceneFace, type NautSceneName, type NautSceneProps, } from './components/naut-scene.js';
73
73
  export { TranscriptionOverlay, type TranscriptionOverlayLabels, type TranscriptionOverlayProps, type TranscriptionOverlaySelector, type TranscriptionOverlayState, } from './components/transcription-overlay.js';
74
74
  export { TimestampedTranscript, type TimestampedTranscriptLabels, type TimestampedTranscriptProps, type TimestampedTranscriptUtterance, type TimestampedTranscriptWord, } from './components/timestamped-transcript.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atmos.build/ui",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "The complete atmOS React component system and MCP App authoring helpers.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",