@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-
|
|
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 =
|
|
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
|
-
|
|
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';
|