@echothink-ui/motion 0.1.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.
Files changed (37) hide show
  1. package/README.md +5 -0
  2. package/dist/components/AgentThinkingAnimation.d.ts +2 -0
  3. package/dist/components/AttentionPulse.d.ts +2 -0
  4. package/dist/components/DAGStatusTransition.d.ts +2 -0
  5. package/dist/components/DocumentLockPulse.d.ts +2 -0
  6. package/dist/components/PipelineFlowAnimation.d.ts +2 -0
  7. package/dist/components/ProgressTransition.d.ts +2 -0
  8. package/dist/components/SkeletonLoadingPattern.d.ts +2 -0
  9. package/dist/components/StatusChangeAnimation.d.ts +2 -0
  10. package/dist/components/StepCompletionAnimation.d.ts +2 -0
  11. package/dist/components/StreamingText.d.ts +2 -0
  12. package/dist/components/SyncProgressAnimation.d.ts +2 -0
  13. package/dist/components/motionUtils.d.ts +5 -0
  14. package/dist/components/types.d.ts +82 -0
  15. package/dist/index.cjs +2381 -0
  16. package/dist/index.cjs.map +1 -0
  17. package/dist/index.d.ts +14 -0
  18. package/dist/index.js +2333 -0
  19. package/dist/index.js.map +1 -0
  20. package/package.json +38 -0
  21. package/src/components/AgentThinkingAnimation.tsx +59 -0
  22. package/src/components/AttentionPulse.tsx +57 -0
  23. package/src/components/DAGStatusTransition.tsx +292 -0
  24. package/src/components/DocumentLockPulse.tsx +72 -0
  25. package/src/components/PipelineFlowAnimation.tsx +243 -0
  26. package/src/components/ProgressTransition.tsx +51 -0
  27. package/src/components/SkeletonLoadingPattern.tsx +248 -0
  28. package/src/components/StatusChangeAnimation.test.tsx +20 -0
  29. package/src/components/StatusChangeAnimation.tsx +89 -0
  30. package/src/components/StepCompletionAnimation.tsx +75 -0
  31. package/src/components/StreamingText.tsx +77 -0
  32. package/src/components/SyncProgressAnimation.test.tsx +49 -0
  33. package/src/components/SyncProgressAnimation.tsx +256 -0
  34. package/src/components/motionUtils.tsx +942 -0
  35. package/src/components/types.ts +111 -0
  36. package/src/index.test.tsx +97 -0
  37. package/src/index.tsx +44 -0
package/dist/index.cjs ADDED
@@ -0,0 +1,2381 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.tsx
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ AgentThinkingAnimation: () => AgentThinkingAnimation,
34
+ AttentionPulse: () => AttentionPulse,
35
+ DAGStatusTransition: () => DAGStatusTransition,
36
+ DocumentLockPulse: () => DocumentLockPulse,
37
+ MotionComponentNames: () => MotionComponentNames,
38
+ PipelineFlowAnimation: () => PipelineFlowAnimation,
39
+ ProgressTransition: () => ProgressTransition,
40
+ SkeletonLoadingPattern: () => SkeletonLoadingPattern,
41
+ StatusChangeAnimation: () => StatusChangeAnimation,
42
+ StepCompletionAnimation: () => StepCompletionAnimation,
43
+ StreamingText: () => StreamingText,
44
+ SyncProgressAnimation: () => SyncProgressAnimation
45
+ });
46
+ module.exports = __toCommonJS(index_exports);
47
+
48
+ // src/components/motionUtils.tsx
49
+ var React = __toESM(require("react"), 1);
50
+ var import_jsx_runtime = require("react/jsx-runtime");
51
+ var reducedMotionQuery = "(prefers-reduced-motion: reduce)";
52
+ function usePrefersReducedMotion() {
53
+ return React.useSyncExternalStore(
54
+ subscribeToReducedMotion,
55
+ getReducedMotionSnapshot,
56
+ getReducedMotionServerSnapshot
57
+ );
58
+ }
59
+ function subscribeToReducedMotion(onStoreChange) {
60
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") {
61
+ return () => {
62
+ };
63
+ }
64
+ const media = window.matchMedia(reducedMotionQuery);
65
+ const listener = () => onStoreChange();
66
+ media.addEventListener?.("change", listener);
67
+ return () => media.removeEventListener?.("change", listener);
68
+ }
69
+ function getReducedMotionSnapshot() {
70
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") return false;
71
+ return window.matchMedia(reducedMotionQuery).matches;
72
+ }
73
+ function getReducedMotionServerSnapshot() {
74
+ return false;
75
+ }
76
+ function MotionStyles() {
77
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: `
78
+ @keyframes eth-motion-flow-dash { to { stroke-dashoffset: -24; } }
79
+ @keyframes eth-motion-pulse { 0% { transform: scale(1); opacity: 1; } 50% { transform: scale(1.035); opacity: .72; } 100% { transform: scale(1); opacity: 1; } }
80
+ @keyframes eth-motion-attention-ring { 0% { opacity: .52; transform: scale(.64); } 70%, 100% { opacity: 0; transform: scale(1.8); } }
81
+ @keyframes eth-motion-flow-node-pulse { 0% { opacity: .42; stroke-width: 1; } 100% { opacity: 0; stroke-width: 7; } }
82
+ @keyframes eth-motion-dot { 0%, 80%, 100% { opacity: .28; transform: translateY(0); } 40% { opacity: 1; transform: translateY(-3px); } }
83
+ @keyframes eth-motion-spin { to { transform: rotate(360deg); } }
84
+ @keyframes eth-motion-sync-sweep { 0% { transform: translateX(-120%); } 100% { transform: translateX(320%); } }
85
+ @keyframes eth-motion-shimmer { 0% { background-position: 100% 0; } 100% { background-position: -100% 0; } }
86
+ @keyframes eth-motion-check { 0% { transform: scale(.78); opacity: 0; } 100% { transform: scale(1); opacity: 1; } }
87
+ @keyframes eth-motion-step-check { 0% { stroke-dashoffset: 18; } 100% { stroke-dashoffset: 0; } }
88
+ @keyframes eth-motion-step-current { 0% { box-shadow: 0 0 0 0 rgba(15, 98, 254, .24); } 100% { box-shadow: 0 0 0 .375rem rgba(15, 98, 254, 0); } }
89
+ @keyframes eth-motion-status-ring { 0% { stroke-dashoffset: 18; opacity: .18; } 55% { opacity: .48; } 100% { stroke-dashoffset: 0; opacity: .32; } }
90
+ @keyframes eth-motion-status-halo { 0% { opacity: .36; transform: scale(.68); } 100% { opacity: 0; transform: scale(1.85); } }
91
+ @keyframes eth-motion-lock-pulse { 0% { opacity: .34; transform: scale(.72); } 70%, 100% { opacity: 0; transform: scale(1.72); } }
92
+ @keyframes eth-motion-stream-cursor { 0%, 46% { opacity: 1; } 47%, 100% { opacity: 0; } }
93
+ .eth-motion-streaming-text {
94
+ align-items: baseline;
95
+ color: var(--cds-text-primary, #161616);
96
+ display: inline-flex;
97
+ font-family: var(--cds-font-family, "IBM Plex Sans", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif);
98
+ font-size: inherit;
99
+ line-height: inherit;
100
+ max-inline-size: 100%;
101
+ min-inline-size: 0;
102
+ overflow-wrap: anywhere;
103
+ white-space: pre-wrap;
104
+ }
105
+ .eth-motion-streaming-text__content {
106
+ min-inline-size: 0;
107
+ }
108
+ .eth-motion-streaming-text__cursor {
109
+ background: var(--cds-interactive, #0f62fe);
110
+ block-size: 1em;
111
+ display: inline-block;
112
+ flex: 0 0 auto;
113
+ inline-size: 2px;
114
+ margin-inline-start: .125rem;
115
+ transform: translateY(.125em);
116
+ }
117
+ .eth-motion-streaming-text--streaming .eth-motion-streaming-text__cursor {
118
+ animation: eth-motion-stream-cursor 1s steps(1, end) infinite;
119
+ }
120
+ .eth-motion-streaming-text--complete .eth-motion-streaming-text__cursor {
121
+ inline-size: 0;
122
+ margin-inline-start: 0;
123
+ opacity: 0;
124
+ }
125
+ .eth-motion-pipeline-flow {
126
+ color: var(--cds-text-primary, #161616);
127
+ display: block;
128
+ font-family: var(--cds-font-family, "IBM Plex Sans", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif);
129
+ inline-size: fit-content;
130
+ max-inline-size: 100%;
131
+ }
132
+ .eth-motion-pipeline-flow__svg {
133
+ block-size: auto;
134
+ display: block;
135
+ font-family: inherit;
136
+ max-inline-size: 100%;
137
+ overflow: visible;
138
+ }
139
+ .eth-motion-pipeline-flow__edge {
140
+ stroke-linecap: round;
141
+ stroke-linejoin: round;
142
+ vector-effect: non-scaling-stroke;
143
+ }
144
+ .eth-motion-pipeline-flow__card {
145
+ fill: var(--cds-layer-02, #ffffff);
146
+ shape-rendering: crispEdges;
147
+ stroke: var(--cds-border-subtle, #e0e0e0);
148
+ stroke-width: 1;
149
+ vector-effect: non-scaling-stroke;
150
+ }
151
+ .eth-motion-pipeline-flow__node--active .eth-motion-pipeline-flow__card {
152
+ fill: var(--cds-layer-01, #f4f4f4);
153
+ stroke: var(--cds-border-strong, #8d8d8d);
154
+ }
155
+ .eth-motion-pipeline-flow__stripe {
156
+ shape-rendering: crispEdges;
157
+ }
158
+ .eth-motion-pipeline-flow__pulse {
159
+ animation: eth-motion-flow-node-pulse 1.3s var(--cds-productive-standard-easing, cubic-bezier(.2, 0, .38, .9)) infinite;
160
+ vector-effect: non-scaling-stroke;
161
+ }
162
+ .eth-motion-pipeline-flow__dot {
163
+ stroke: var(--cds-layer-02, #ffffff);
164
+ stroke-width: 2;
165
+ vector-effect: non-scaling-stroke;
166
+ }
167
+ .eth-motion-pipeline-flow__label {
168
+ fill: var(--cds-text-primary, #161616);
169
+ font-size: 13px;
170
+ font-weight: 600;
171
+ }
172
+ .eth-motion-pipeline-flow__status {
173
+ fill: var(--cds-text-secondary, #525252);
174
+ font-size: 11px;
175
+ }
176
+ .eth-motion-pipeline-flow__empty {
177
+ fill: var(--cds-text-secondary, #525252);
178
+ font-size: 13px;
179
+ }
180
+ .eth-motion-pipeline-flow__fallback {
181
+ block-size: 1px;
182
+ clip: rect(0 0 0 0);
183
+ clip-path: inset(50%);
184
+ inline-size: 1px;
185
+ margin: 0;
186
+ overflow: hidden;
187
+ padding: 0;
188
+ position: absolute;
189
+ white-space: nowrap;
190
+ }
191
+ .eth-motion-dag-status {
192
+ color: var(--cds-text-primary, #161616);
193
+ display: block;
194
+ max-inline-size: 100%;
195
+ }
196
+ .eth-motion-dag-status__svg {
197
+ block-size: auto;
198
+ display: block;
199
+ font-family: var(--cds-font-family, "IBM Plex Sans", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif);
200
+ max-inline-size: 100%;
201
+ overflow: visible;
202
+ }
203
+ .eth-motion-dag-status__edge {
204
+ stroke-linecap: round;
205
+ stroke-linejoin: round;
206
+ vector-effect: non-scaling-stroke;
207
+ }
208
+ .eth-motion-dag-status__card {
209
+ shape-rendering: crispEdges;
210
+ stroke-width: 1;
211
+ vector-effect: non-scaling-stroke;
212
+ }
213
+ .eth-motion-dag-status__change-ring {
214
+ animation: eth-motion-status-ring 700ms var(--cds-productive-standard-easing, cubic-bezier(.2, 0, .38, .9)) 1;
215
+ stroke-dasharray: 4 4;
216
+ stroke-width: 1;
217
+ vector-effect: non-scaling-stroke;
218
+ }
219
+ .eth-motion-dag-status__label {
220
+ fill: var(--cds-text-primary, #161616);
221
+ font-size: 13px;
222
+ font-weight: 600;
223
+ }
224
+ .eth-motion-dag-status__status {
225
+ fill: var(--cds-text-secondary, #525252);
226
+ font-size: 11px;
227
+ }
228
+ .eth-motion-dag-status__fallback {
229
+ block-size: 1px;
230
+ clip: rect(0 0 0 0);
231
+ clip-path: inset(50%);
232
+ inline-size: 1px;
233
+ margin: 0;
234
+ overflow: hidden;
235
+ padding: 0;
236
+ position: absolute;
237
+ white-space: nowrap;
238
+ }
239
+ .eth-motion-sync-progress {
240
+ --eth-motion-sync-accent: var(--cds-interactive, #0f62fe);
241
+ --eth-motion-sync-accent-soft: var(--cds-highlight, #edf5ff);
242
+
243
+ box-sizing: border-box;
244
+ color: var(--cds-text-primary, #161616);
245
+ font-family: var(--cds-font-family, "IBM Plex Sans", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif);
246
+ line-height: 1.2857;
247
+ max-inline-size: 100%;
248
+ min-inline-size: 0;
249
+ }
250
+ .eth-motion-sync-progress *,
251
+ .eth-motion-sync-progress *::before,
252
+ .eth-motion-sync-progress *::after {
253
+ box-sizing: border-box;
254
+ }
255
+ .eth-motion-sync-progress--compact {
256
+ align-items: center;
257
+ background: var(--cds-layer-01, #ffffff);
258
+ border: 1px solid var(--cds-border-subtle-01, var(--cds-border-subtle, #e0e0e0));
259
+ border-inline-start: 3px solid var(--eth-motion-sync-accent);
260
+ display: inline-flex;
261
+ gap: var(--cds-spacing-03, .5rem);
262
+ inline-size: fit-content;
263
+ min-block-size: 2rem;
264
+ padding: .375rem .75rem .375rem .625rem;
265
+ vertical-align: middle;
266
+ }
267
+ .eth-motion-sync-progress--detailed {
268
+ align-items: stretch;
269
+ background: var(--cds-layer-01, #ffffff);
270
+ border: 1px solid var(--cds-border-subtle-01, var(--cds-border-subtle, #e0e0e0));
271
+ border-inline-start: 4px solid var(--eth-motion-sync-accent);
272
+ display: grid;
273
+ grid-template-columns: 1.5rem minmax(0, 1fr);
274
+ inline-size: 100%;
275
+ max-inline-size: 52rem;
276
+ min-block-size: 7.5rem;
277
+ }
278
+ .eth-motion-sync-progress__indicator {
279
+ align-items: center;
280
+ color: var(--eth-motion-sync-accent);
281
+ display: inline-flex;
282
+ flex: 0 0 auto;
283
+ inline-size: 1.125rem;
284
+ justify-content: center;
285
+ }
286
+ .eth-motion-sync-progress--detailed .eth-motion-sync-progress__indicator {
287
+ align-items: start;
288
+ inline-size: auto;
289
+ justify-content: center;
290
+ padding-block-start: var(--cds-spacing-05, 1rem);
291
+ padding-inline-start: var(--cds-spacing-04, .75rem);
292
+ }
293
+ .eth-motion-sync-progress__spinner,
294
+ .eth-motion-sync-progress__glyph {
295
+ block-size: 1rem;
296
+ border-radius: 50%;
297
+ display: inline-block;
298
+ inline-size: 1rem;
299
+ }
300
+ .eth-motion-sync-progress__spinner {
301
+ animation: eth-motion-spin 850ms linear infinite;
302
+ border: 2px solid var(--cds-border-subtle-01, #c6c6c6);
303
+ border-block-start-color: var(--eth-motion-sync-accent);
304
+ }
305
+ .eth-motion-sync-progress__glyph {
306
+ background: var(--eth-motion-sync-accent);
307
+ box-shadow: inset 0 0 0 3px var(--cds-layer-01, #ffffff);
308
+ }
309
+ .eth-motion-sync-progress__compact-copy {
310
+ align-items: baseline;
311
+ display: inline-flex;
312
+ gap: var(--cds-spacing-03, .5rem);
313
+ min-inline-size: 0;
314
+ }
315
+ .eth-motion-sync-progress__label {
316
+ color: var(--cds-text-primary, #161616);
317
+ font-size: var(--cds-body-compact-01-font-size, .875rem);
318
+ font-weight: 600;
319
+ line-height: var(--cds-body-compact-01-line-height, 1.2857);
320
+ min-inline-size: 0;
321
+ overflow-wrap: anywhere;
322
+ }
323
+ .eth-motion-sync-progress__compact-state {
324
+ color: var(--cds-text-secondary, #525252);
325
+ flex: 0 0 auto;
326
+ font-size: var(--cds-label-01-font-size, .75rem);
327
+ line-height: var(--cds-label-01-line-height, 1.3333);
328
+ white-space: nowrap;
329
+ }
330
+ .eth-motion-sync-progress__body {
331
+ display: grid;
332
+ gap: var(--cds-spacing-04, .75rem);
333
+ min-inline-size: 0;
334
+ padding: var(--cds-spacing-05, 1rem);
335
+ }
336
+ .eth-motion-sync-progress__header {
337
+ align-items: start;
338
+ display: flex;
339
+ gap: var(--cds-spacing-04, .75rem);
340
+ justify-content: space-between;
341
+ min-inline-size: 0;
342
+ }
343
+ .eth-motion-sync-progress__title-group {
344
+ display: grid;
345
+ gap: var(--cds-spacing-01, .125rem);
346
+ min-inline-size: 0;
347
+ }
348
+ .eth-motion-sync-progress__eyebrow,
349
+ .eth-motion-sync-progress__description,
350
+ .eth-motion-sync-progress__progress-copy,
351
+ .eth-motion-sync-progress__meta dt {
352
+ color: var(--cds-text-secondary, #525252);
353
+ font-size: var(--cds-label-01-font-size, .75rem);
354
+ line-height: var(--cds-label-01-line-height, 1.3333);
355
+ }
356
+ .eth-motion-sync-progress__eyebrow,
357
+ .eth-motion-sync-progress__meta dt {
358
+ font-weight: 600;
359
+ text-transform: uppercase;
360
+ }
361
+ .eth-motion-sync-progress__description {
362
+ margin: 0;
363
+ max-inline-size: 38rem;
364
+ overflow-wrap: anywhere;
365
+ }
366
+ .eth-motion-sync-progress__chip {
367
+ align-items: center;
368
+ background: var(--eth-motion-sync-accent-soft);
369
+ border: 1px solid var(--cds-border-subtle-01, var(--cds-border-subtle, #e0e0e0));
370
+ color: var(--cds-text-primary, #161616);
371
+ display: inline-flex;
372
+ flex: 0 0 auto;
373
+ font-size: var(--cds-label-01-font-size, .75rem);
374
+ font-weight: 600;
375
+ gap: var(--cds-spacing-02, .25rem);
376
+ line-height: var(--cds-label-01-line-height, 1.3333);
377
+ min-block-size: 1.5rem;
378
+ padding: .1875rem var(--cds-spacing-03, .5rem);
379
+ white-space: nowrap;
380
+ }
381
+ .eth-motion-sync-progress__chip-dot {
382
+ background: var(--eth-motion-sync-accent);
383
+ block-size: .5rem;
384
+ border-radius: 50%;
385
+ display: inline-block;
386
+ inline-size: .5rem;
387
+ }
388
+ .eth-motion-sync-progress__meter {
389
+ display: grid;
390
+ gap: var(--cds-spacing-03, .5rem);
391
+ min-inline-size: 0;
392
+ }
393
+ .eth-motion-sync-progress__track {
394
+ background: var(--cds-border-subtle-01, var(--cds-border-subtle, #e0e0e0));
395
+ block-size: .5rem;
396
+ inline-size: 100%;
397
+ overflow: hidden;
398
+ position: relative;
399
+ }
400
+ .eth-motion-sync-progress__bar {
401
+ background: var(--eth-motion-sync-accent);
402
+ block-size: 100%;
403
+ display: block;
404
+ min-inline-size: .25rem;
405
+ transition: inline-size var(--cds-duration-fast-02, 110ms)
406
+ var(--cds-productive-standard-easing, cubic-bezier(.2, 0, .38, .9));
407
+ }
408
+ .eth-motion-sync-progress__bar--indeterminate {
409
+ animation: eth-motion-sync-sweep 1.35s var(--cds-productive-standard-easing, cubic-bezier(.2, 0, .38, .9)) infinite;
410
+ inline-size: 34%;
411
+ }
412
+ .eth-motion-sync-progress__progress-copy {
413
+ font-variant-numeric: tabular-nums;
414
+ justify-self: end;
415
+ }
416
+ .eth-motion-sync-progress__meta {
417
+ background: var(--cds-layer-02, #f4f4f4);
418
+ border-block-start: 1px solid var(--cds-border-subtle-01, var(--cds-border-subtle, #e0e0e0));
419
+ display: grid;
420
+ gap: 0;
421
+ grid-column: 1 / -1;
422
+ grid-template-columns: repeat(auto-fit, minmax(min(100%, 10rem), 1fr));
423
+ margin: 0;
424
+ min-inline-size: 0;
425
+ }
426
+ .eth-motion-sync-progress__meta-item {
427
+ display: grid;
428
+ gap: var(--cds-spacing-02, .25rem);
429
+ min-inline-size: 0;
430
+ padding: var(--cds-spacing-04, .75rem) var(--cds-spacing-05, 1rem);
431
+ }
432
+ .eth-motion-sync-progress__meta-item + .eth-motion-sync-progress__meta-item {
433
+ border-inline-start: 1px solid var(--cds-border-subtle-01, var(--cds-border-subtle, #e0e0e0));
434
+ }
435
+ .eth-motion-sync-progress__meta dd {
436
+ color: var(--cds-text-primary, #161616);
437
+ font-size: var(--cds-body-compact-01-font-size, .875rem);
438
+ font-weight: 600;
439
+ line-height: var(--cds-body-compact-01-line-height, 1.2857);
440
+ margin: 0;
441
+ min-inline-size: 0;
442
+ overflow-wrap: anywhere;
443
+ }
444
+ .eth-motion-sync-progress.eth-motion-reduced .eth-motion-sync-progress__bar--indeterminate {
445
+ animation: none;
446
+ inline-size: 38%;
447
+ }
448
+ .eth-motion-skeleton-loading {
449
+ color: var(--cds-text-primary, #161616);
450
+ display: block;
451
+ font-family: var(--cds-font-family, "IBM Plex Sans", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif);
452
+ inline-size: 100%;
453
+ max-inline-size: 100%;
454
+ min-inline-size: 0;
455
+ }
456
+ .eth-motion-skeleton-loading__surface {
457
+ background: var(--cds-layer-01, #f4f4f4);
458
+ border: 1px solid var(--cds-border-subtle, #e0e0e0);
459
+ display: grid;
460
+ inline-size: 100%;
461
+ min-inline-size: 0;
462
+ overflow: hidden;
463
+ }
464
+ .eth-motion-skeleton-loading__block {
465
+ background: var(--cds-skeleton-background, #e0e0e0);
466
+ block-size: .875rem;
467
+ display: block;
468
+ inline-size: 100%;
469
+ min-inline-size: .75rem;
470
+ }
471
+ .eth-motion-skeleton-loading:not(.eth-motion-reduced) .eth-motion-skeleton-loading__block {
472
+ animation: eth-motion-shimmer 1.2s var(--cds-productive-standard-easing, cubic-bezier(.2, 0, .38, .9)) infinite;
473
+ background-image: linear-gradient(
474
+ 90deg,
475
+ var(--cds-skeleton-background, #e0e0e0) 0%,
476
+ var(--cds-skeleton-element, #f4f4f4) 46%,
477
+ var(--cds-skeleton-background, #e0e0e0) 82%
478
+ );
479
+ background-size: 200% 100%;
480
+ }
481
+ .eth-motion-skeleton-loading__surface--article {
482
+ gap: var(--cds-spacing-05, 1rem);
483
+ padding: var(--cds-spacing-05, 1rem);
484
+ }
485
+ .eth-motion-skeleton-loading__article-header,
486
+ .eth-motion-skeleton-loading__article-body,
487
+ .eth-motion-skeleton-loading__card-body,
488
+ .eth-motion-skeleton-loading__list-copy {
489
+ display: grid;
490
+ gap: var(--cds-spacing-03, .5rem);
491
+ min-inline-size: 0;
492
+ }
493
+ .eth-motion-skeleton-loading__article-body,
494
+ .eth-motion-skeleton-loading__card-body {
495
+ gap: var(--cds-spacing-04, .75rem);
496
+ }
497
+ .eth-motion-skeleton-loading__block--eyebrow {
498
+ block-size: .5rem;
499
+ }
500
+ .eth-motion-skeleton-loading__block--title {
501
+ block-size: 1.125rem;
502
+ }
503
+ .eth-motion-skeleton-loading__block--caption,
504
+ .eth-motion-skeleton-loading__block--column {
505
+ block-size: .625rem;
506
+ }
507
+ .eth-motion-skeleton-loading__surface--card {
508
+ background: var(--cds-layer-01, #ffffff);
509
+ }
510
+ .eth-motion-skeleton-loading__block--media {
511
+ block-size: 6rem;
512
+ inline-size: 100%;
513
+ }
514
+ .eth-motion-skeleton-loading__card-body {
515
+ padding: var(--cds-spacing-05, 1rem);
516
+ }
517
+ .eth-motion-skeleton-loading__card-metrics {
518
+ border-block-start: 1px solid var(--cds-border-subtle, #e0e0e0);
519
+ display: grid;
520
+ gap: var(--cds-spacing-05, 1rem);
521
+ grid-template-columns: repeat(3, minmax(0, 1fr));
522
+ padding: var(--cds-spacing-04, .75rem) var(--cds-spacing-05, 1rem);
523
+ }
524
+ .eth-motion-skeleton-loading__block--metric {
525
+ block-size: 1.5rem;
526
+ }
527
+ .eth-motion-skeleton-loading__list-row {
528
+ align-items: center;
529
+ display: grid;
530
+ gap: var(--cds-spacing-04, .75rem);
531
+ grid-template-columns: 2rem minmax(0, 1fr) minmax(3rem, 5rem);
532
+ min-block-size: 4rem;
533
+ padding: var(--cds-spacing-04, .75rem);
534
+ }
535
+ .eth-motion-skeleton-loading__list-row + .eth-motion-skeleton-loading__list-row {
536
+ border-block-start: 1px solid var(--cds-border-subtle, #e0e0e0);
537
+ }
538
+ .eth-motion-skeleton-loading__block--avatar {
539
+ block-size: 2rem;
540
+ inline-size: 2rem;
541
+ }
542
+ .eth-motion-skeleton-loading__block--tag {
543
+ block-size: 1.25rem;
544
+ justify-self: end;
545
+ }
546
+ .eth-motion-skeleton-loading__surface--table {
547
+ background: var(--cds-layer-01, #ffffff);
548
+ }
549
+ .eth-motion-skeleton-loading__table-header,
550
+ .eth-motion-skeleton-loading__table-row {
551
+ display: grid;
552
+ gap: var(--cds-spacing-05, 1rem);
553
+ min-inline-size: 0;
554
+ }
555
+ .eth-motion-skeleton-loading__table-header {
556
+ align-items: center;
557
+ background: var(--cds-layer-02, #f4f4f4);
558
+ min-block-size: 2.5rem;
559
+ padding: var(--cds-spacing-04, .75rem);
560
+ }
561
+ .eth-motion-skeleton-loading__table-row {
562
+ align-items: center;
563
+ border-block-start: 1px solid var(--cds-border-subtle, #e0e0e0);
564
+ min-block-size: 3rem;
565
+ padding: var(--cds-spacing-04, .75rem);
566
+ }
567
+ .eth-motion-skeleton-loading__block--cell {
568
+ block-size: .75rem;
569
+ }
570
+ @media (max-width: 42rem) {
571
+ .eth-motion-sync-progress__header {
572
+ align-items: stretch;
573
+ flex-direction: column;
574
+ }
575
+ .eth-motion-sync-progress__chip {
576
+ align-self: start;
577
+ }
578
+ .eth-motion-sync-progress__meta {
579
+ grid-template-columns: minmax(0, 1fr);
580
+ }
581
+ .eth-motion-sync-progress__meta-item + .eth-motion-sync-progress__meta-item {
582
+ border-block-start: 1px solid var(--cds-border-subtle-01, var(--cds-border-subtle, #e0e0e0));
583
+ border-inline-start: 0;
584
+ }
585
+ .eth-motion-skeleton-loading__list-row {
586
+ grid-template-columns: 2rem minmax(0, 1fr);
587
+ }
588
+ .eth-motion-skeleton-loading__block--tag {
589
+ display: none;
590
+ }
591
+ .eth-motion-skeleton-loading__table-header,
592
+ .eth-motion-skeleton-loading__table-row {
593
+ gap: var(--cds-spacing-04, .75rem);
594
+ }
595
+ }
596
+ .eth-motion-status-change {
597
+ --eth-motion-status-color: var(--cds-interactive, #0f62fe);
598
+ --eth-motion-status-previous-color: var(--cds-text-secondary, #525252);
599
+
600
+ align-items: center;
601
+ background: var(--cds-layer-01, #ffffff);
602
+ border: 1px solid var(--cds-border-subtle-01, var(--cds-border-subtle, #e0e0e0));
603
+ border-inline-start: 3px solid var(--eth-motion-status-color);
604
+ border-radius: var(--cds-radius-sm, 2px);
605
+ box-sizing: border-box;
606
+ color: var(--cds-text-primary, #161616);
607
+ display: inline-flex;
608
+ font-family: var(--cds-font-family, "IBM Plex Sans", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif);
609
+ gap: var(--cds-spacing-04, .75rem);
610
+ inline-size: fit-content;
611
+ line-height: 1.2857;
612
+ max-inline-size: 100%;
613
+ min-block-size: 2.5rem;
614
+ padding: .5rem .75rem .5rem .625rem;
615
+ vertical-align: middle;
616
+ }
617
+ .eth-motion-status-change--changed {
618
+ animation: eth-motion-pulse 650ms var(--cds-productive-standard-easing, cubic-bezier(.2, 0, .38, .9)) 1;
619
+ background: var(--cds-layer-02, #f4f4f4);
620
+ }
621
+ .eth-motion-status-change__indicator {
622
+ align-items: center;
623
+ display: inline-flex;
624
+ flex: 0 0 auto;
625
+ inline-size: 2.5rem;
626
+ }
627
+ .eth-motion-status-change__previous-dot,
628
+ .eth-motion-status-change__current-dot {
629
+ border-radius: 50%;
630
+ box-sizing: border-box;
631
+ display: inline-block;
632
+ flex: 0 0 auto;
633
+ }
634
+ .eth-motion-status-change__previous-dot {
635
+ background: var(--eth-motion-status-previous-color);
636
+ block-size: .5rem;
637
+ inline-size: .5rem;
638
+ opacity: .64;
639
+ }
640
+ .eth-motion-status-change__connector {
641
+ background: var(--cds-border-strong-01, #8d8d8d);
642
+ block-size: 1px;
643
+ flex: 1 1 auto;
644
+ margin-inline: .25rem;
645
+ min-inline-size: .625rem;
646
+ }
647
+ .eth-motion-status-change__current-dot {
648
+ background: var(--eth-motion-status-color);
649
+ block-size: .625rem;
650
+ box-shadow: 0 0 0 2px var(--cds-layer-01, #ffffff);
651
+ inline-size: .625rem;
652
+ position: relative;
653
+ }
654
+ .eth-motion-status-change--changed .eth-motion-status-change__current-dot::after {
655
+ animation: eth-motion-status-halo 700ms var(--cds-productive-standard-easing, cubic-bezier(.2, 0, .38, .9)) 1;
656
+ border: 1px solid var(--eth-motion-status-color);
657
+ border-radius: 50%;
658
+ content: "";
659
+ inset: -.375rem;
660
+ opacity: 0;
661
+ position: absolute;
662
+ }
663
+ .eth-motion-status-change__content {
664
+ display: grid;
665
+ gap: var(--cds-spacing-01, .125rem);
666
+ min-inline-size: 0;
667
+ }
668
+ .eth-motion-status-change__label {
669
+ color: var(--cds-text-primary, #161616);
670
+ font-size: var(--cds-body-compact-01-font-size, .875rem);
671
+ font-weight: 600;
672
+ line-height: var(--cds-body-compact-01-line-height, 1.2857);
673
+ min-inline-size: 0;
674
+ overflow-wrap: anywhere;
675
+ }
676
+ .eth-motion-status-change__state {
677
+ align-items: center;
678
+ color: var(--cds-text-secondary, #525252);
679
+ display: flex;
680
+ flex-wrap: wrap;
681
+ font-size: var(--cds-label-01-font-size, .75rem);
682
+ gap: var(--cds-spacing-02, .25rem);
683
+ line-height: var(--cds-label-01-line-height, 1.3333);
684
+ min-inline-size: 0;
685
+ }
686
+ .eth-motion-status-change__previous,
687
+ .eth-motion-status-change__current {
688
+ overflow-wrap: anywhere;
689
+ }
690
+ .eth-motion-status-change__current {
691
+ color: var(--cds-text-primary, #161616);
692
+ font-weight: 600;
693
+ }
694
+ .eth-motion-status-change__separator {
695
+ color: var(--cds-text-secondary, #525252);
696
+ }
697
+ .eth-motion-attention-pulse {
698
+ --eth-motion-attention-color: var(--cds-support-warning, #f1c21b);
699
+ --eth-motion-attention-border: #8a6a00;
700
+ --eth-motion-attention-ink: var(--cds-text-primary, #161616);
701
+ --eth-motion-attention-repeat: infinite;
702
+
703
+ align-items: center;
704
+ background: var(--cds-layer-02, #ffffff);
705
+ border: 1px solid var(--cds-border-subtle, #e0e0e0);
706
+ border-radius: var(--cds-radius-sm, 2px);
707
+ box-shadow: inset 3px 0 0 var(--eth-motion-attention-color);
708
+ color: var(--cds-text-primary, #161616);
709
+ display: inline-flex;
710
+ font-size: .875rem;
711
+ font-weight: 500;
712
+ gap: var(--cds-spacing-03, .5rem);
713
+ inline-size: fit-content;
714
+ line-height: 1.2857;
715
+ max-inline-size: 100%;
716
+ min-block-size: 2rem;
717
+ padding: .375rem .75rem .375rem .625rem;
718
+ vertical-align: middle;
719
+ }
720
+ .eth-motion-attention-pulse__marker {
721
+ align-items: center;
722
+ block-size: 1rem;
723
+ display: inline-flex;
724
+ flex: 0 0 auto;
725
+ inline-size: 1rem;
726
+ justify-content: center;
727
+ position: relative;
728
+ }
729
+ .eth-motion-attention-pulse__marker::before {
730
+ animation: eth-motion-attention-ring 1.4s var(--cds-productive-standard-easing, cubic-bezier(.2, 0, .38, .9)) var(--eth-motion-attention-repeat);
731
+ border: 1px solid var(--eth-motion-attention-color);
732
+ border-radius: 50%;
733
+ content: "";
734
+ inset: -.125rem;
735
+ position: absolute;
736
+ }
737
+ .eth-motion-attention-pulse__dot {
738
+ align-items: center;
739
+ background: var(--eth-motion-attention-color);
740
+ block-size: 1rem;
741
+ border: 1px solid var(--eth-motion-attention-border);
742
+ border-radius: 50%;
743
+ color: var(--eth-motion-attention-ink);
744
+ display: inline-flex;
745
+ font-size: .6875rem;
746
+ font-weight: 700;
747
+ inline-size: 1rem;
748
+ justify-content: center;
749
+ line-height: 1;
750
+ position: relative;
751
+ }
752
+ .eth-motion-attention-pulse__label {
753
+ min-inline-size: 0;
754
+ overflow-wrap: anywhere;
755
+ }
756
+ .eth-motion-attention-pulse.eth-motion-reduced .eth-motion-attention-pulse__marker::before {
757
+ animation: none;
758
+ opacity: .32;
759
+ transform: scale(1);
760
+ }
761
+ .eth-motion-document-lock {
762
+ --eth-motion-document-lock-accent: var(--cds-interactive, #0f62fe);
763
+
764
+ align-items: center;
765
+ background: var(--cds-layer-01, #ffffff);
766
+ border: 1px solid var(--cds-border-subtle-01, var(--cds-border-subtle, #e0e0e0));
767
+ border-inline-start: 3px solid var(--cds-border-strong-01, #8d8d8d);
768
+ box-sizing: border-box;
769
+ color: var(--cds-text-primary, #161616);
770
+ display: inline-flex;
771
+ font-family: var(--cds-font-family, "IBM Plex Sans", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif);
772
+ gap: var(--cds-spacing-03, .5rem);
773
+ inline-size: fit-content;
774
+ line-height: 1.2857;
775
+ max-inline-size: 100%;
776
+ min-block-size: 2.5rem;
777
+ padding: .375rem .75rem .375rem .625rem;
778
+ vertical-align: middle;
779
+ }
780
+ .eth-motion-document-lock--active {
781
+ background: var(--cds-layer-02, #f4f4f4);
782
+ border-inline-start-color: var(--eth-motion-document-lock-accent);
783
+ }
784
+ .eth-motion-document-lock__indicator {
785
+ align-items: center;
786
+ block-size: 1.25rem;
787
+ color: var(--cds-icon-secondary, #525252);
788
+ display: inline-flex;
789
+ flex: 0 0 auto;
790
+ inline-size: 1.25rem;
791
+ justify-content: center;
792
+ position: relative;
793
+ }
794
+ .eth-motion-document-lock--active .eth-motion-document-lock__indicator {
795
+ color: var(--eth-motion-document-lock-accent);
796
+ }
797
+ .eth-motion-document-lock__pulse {
798
+ border: 1px solid currentColor;
799
+ border-radius: 50%;
800
+ inset: .125rem;
801
+ opacity: 0;
802
+ position: absolute;
803
+ }
804
+ .eth-motion-document-lock--active .eth-motion-document-lock__pulse {
805
+ animation: eth-motion-lock-pulse 1.45s var(--cds-productive-standard-easing, cubic-bezier(.2, 0, .38, .9)) infinite;
806
+ opacity: .34;
807
+ }
808
+ .eth-motion-document-lock__icon {
809
+ block-size: 1rem;
810
+ inline-size: 1rem;
811
+ position: relative;
812
+ }
813
+ .eth-motion-document-lock__content {
814
+ display: grid;
815
+ gap: 0;
816
+ min-inline-size: 0;
817
+ }
818
+ .eth-motion-document-lock__state {
819
+ color: var(--cds-text-secondary, #525252);
820
+ font-size: .75rem;
821
+ font-weight: 600;
822
+ line-height: 1.3333;
823
+ }
824
+ .eth-motion-document-lock--active .eth-motion-document-lock__state {
825
+ color: var(--cds-link-primary, #0f62fe);
826
+ }
827
+ .eth-motion-document-lock__owner {
828
+ color: var(--cds-text-primary, #161616);
829
+ font-size: .875rem;
830
+ font-weight: 600;
831
+ line-height: 1.2857;
832
+ overflow-wrap: anywhere;
833
+ }
834
+ .eth-motion-document-lock.eth-motion-reduced .eth-motion-document-lock__pulse {
835
+ animation: none;
836
+ opacity: .18;
837
+ transform: scale(1);
838
+ }
839
+ .eth-motion-step-completion {
840
+ align-items: start;
841
+ color: var(--cds-text-primary, #161616);
842
+ display: inline-grid;
843
+ font-family: var(--cds-font-family, "IBM Plex Sans", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif);
844
+ font-size: var(--cds-body-compact-01-font-size, .875rem);
845
+ gap: var(--cds-spacing-03, .5rem);
846
+ grid-template-columns: 1.5rem minmax(0, 1fr);
847
+ line-height: var(--cds-body-compact-01-line-height, 1.4286);
848
+ max-inline-size: 100%;
849
+ min-inline-size: 0;
850
+ vertical-align: middle;
851
+ }
852
+ .eth-motion-step-completion__marker {
853
+ align-items: center;
854
+ background: var(--cds-layer-01, #ffffff);
855
+ block-size: 1.5rem;
856
+ border: 1px solid var(--cds-border-strong-01, #8d8d8d);
857
+ border-radius: 50%;
858
+ color: var(--cds-icon-secondary, #525252);
859
+ display: inline-flex;
860
+ flex: 0 0 auto;
861
+ inline-size: 1.5rem;
862
+ justify-content: center;
863
+ margin-block-start: .0625rem;
864
+ }
865
+ .eth-motion-step-completion--completed .eth-motion-step-completion__marker {
866
+ animation: eth-motion-check 220ms var(--cds-productive-standard-easing, cubic-bezier(.2, 0, .38, .9)) 1;
867
+ background: var(--cds-support-success, #24a148);
868
+ border-color: var(--cds-support-success, #24a148);
869
+ color: var(--cds-text-on-color, #ffffff);
870
+ }
871
+ .eth-motion-step-completion--current .eth-motion-step-completion__marker {
872
+ animation: eth-motion-step-current 1.25s var(--cds-productive-standard-easing, cubic-bezier(.2, 0, .38, .9)) infinite;
873
+ background: var(--cds-highlight, #edf5ff);
874
+ border-color: var(--cds-interactive, #0f62fe);
875
+ color: var(--cds-interactive, #0f62fe);
876
+ }
877
+ .eth-motion-step-completion--pending .eth-motion-step-completion__marker {
878
+ background: var(--cds-layer-02, #f4f4f4);
879
+ border-color: var(--cds-border-strong-01, #8d8d8d);
880
+ color: var(--cds-icon-secondary, #525252);
881
+ }
882
+ .eth-motion-step-completion__check {
883
+ block-size: 1rem;
884
+ display: block;
885
+ inline-size: 1rem;
886
+ }
887
+ .eth-motion-step-completion__check-path {
888
+ animation: eth-motion-step-check 260ms var(--cds-productive-standard-easing, cubic-bezier(.2, 0, .38, .9)) 90ms both;
889
+ fill: none;
890
+ stroke: currentColor;
891
+ stroke-dasharray: 18;
892
+ stroke-dashoffset: 18;
893
+ stroke-linecap: round;
894
+ stroke-linejoin: round;
895
+ stroke-width: 2;
896
+ }
897
+ .eth-motion-step-completion__dot {
898
+ background: currentColor;
899
+ block-size: .4375rem;
900
+ border-radius: 50%;
901
+ display: block;
902
+ inline-size: .4375rem;
903
+ }
904
+ .eth-motion-step-completion--current .eth-motion-step-completion__dot {
905
+ block-size: .5rem;
906
+ inline-size: .5rem;
907
+ }
908
+ .eth-motion-step-completion__content {
909
+ display: grid;
910
+ gap: .125rem;
911
+ min-inline-size: 0;
912
+ }
913
+ .eth-motion-step-completion__label {
914
+ color: var(--cds-text-primary, #161616);
915
+ font-weight: 600;
916
+ overflow-wrap: anywhere;
917
+ }
918
+ .eth-motion-step-completion__state {
919
+ color: var(--cds-text-secondary, #525252);
920
+ font-size: var(--cds-label-01-font-size, .75rem);
921
+ font-weight: 600;
922
+ line-height: var(--cds-label-01-line-height, 1.3333);
923
+ }
924
+ .eth-motion-step-completion--completed .eth-motion-step-completion__state {
925
+ color: var(--cds-support-success-strong, #198038);
926
+ }
927
+ .eth-motion-step-completion--current .eth-motion-step-completion__state {
928
+ color: var(--cds-link-primary, #0f62fe);
929
+ }
930
+ .eth-motion-step-completion__description {
931
+ color: var(--cds-text-secondary, #525252);
932
+ font-size: var(--cds-label-01-font-size, .75rem);
933
+ line-height: var(--cds-label-01-line-height, 1.3333);
934
+ overflow-wrap: anywhere;
935
+ }
936
+ .eth-motion-step-completion.eth-motion-reduced .eth-motion-step-completion__check-path {
937
+ stroke-dashoffset: 0;
938
+ }
939
+ .eth-motion-reduced,
940
+ .eth-motion-reduced * { animation: none !important; transition: none !important; }
941
+ ` });
942
+ }
943
+ function statusColor(status) {
944
+ switch (status) {
945
+ case "succeeded":
946
+ case "completed":
947
+ case "synced":
948
+ return "#24a148";
949
+ case "failed":
950
+ case "blocked":
951
+ return "#da1e28";
952
+ case "warning":
953
+ case "pending-approval":
954
+ case "approval-required":
955
+ return "#f1c21b";
956
+ case "running":
957
+ case "in-progress":
958
+ case "active":
959
+ return "#0f62fe";
960
+ case "paused":
961
+ case "stale":
962
+ return "#8d8d8d";
963
+ default:
964
+ return "#6f6f6f";
965
+ }
966
+ }
967
+ function severityColor(severity) {
968
+ switch (severity) {
969
+ case "danger":
970
+ return "#da1e28";
971
+ case "warning":
972
+ return "#f1c21b";
973
+ case "success":
974
+ return "#24a148";
975
+ case "info":
976
+ return "#0f62fe";
977
+ default:
978
+ return "#6f6f6f";
979
+ }
980
+ }
981
+
982
+ // src/components/AgentThinkingAnimation.tsx
983
+ var import_jsx_runtime2 = require("react/jsx-runtime");
984
+ function AgentThinkingAnimation({
985
+ label = "Agent thinking",
986
+ className,
987
+ style,
988
+ ...props
989
+ }) {
990
+ const reduced = usePrefersReducedMotion();
991
+ const classes = [
992
+ "eth-motion-agent-thinking",
993
+ reduced ? "eth-motion-reduced" : void 0,
994
+ className
995
+ ].filter(Boolean).join(" ");
996
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
997
+ "span",
998
+ {
999
+ ...props,
1000
+ className: classes,
1001
+ role: "status",
1002
+ "aria-label": label,
1003
+ "data-eth-component": "AgentThinkingAnimation",
1004
+ style: {
1005
+ alignItems: "center",
1006
+ color: "var(--cds-interactive, #0f62fe)",
1007
+ display: "inline-flex",
1008
+ justifyContent: "center",
1009
+ lineHeight: 1,
1010
+ minBlockSize: 16,
1011
+ verticalAlign: "middle",
1012
+ ...style
1013
+ },
1014
+ children: [
1015
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(MotionStyles, {}),
1016
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { "aria-hidden": true, style: { alignItems: "center", display: "inline-flex", gap: 4 }, children: [
1017
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "eth-motion-dot", style: dotStyle(reduced, 0) }),
1018
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "eth-motion-dot", style: dotStyle(reduced, 1) }),
1019
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "eth-motion-dot", style: dotStyle(reduced, 2) })
1020
+ ] })
1021
+ ]
1022
+ }
1023
+ );
1024
+ }
1025
+ function dotStyle(reduced, index) {
1026
+ return {
1027
+ display: "inline-block",
1028
+ width: 6,
1029
+ height: 6,
1030
+ borderRadius: "50%",
1031
+ background: "currentColor",
1032
+ flex: "0 0 auto",
1033
+ animation: reduced ? void 0 : "eth-motion-dot 1s ease-in-out infinite",
1034
+ animationDelay: reduced ? void 0 : `${index * 120}ms`
1035
+ };
1036
+ }
1037
+
1038
+ // src/components/AttentionPulse.tsx
1039
+ var React2 = __toESM(require("react"), 1);
1040
+ var import_jsx_runtime3 = require("react/jsx-runtime");
1041
+ function AttentionPulse({
1042
+ severity = "warning",
1043
+ maxRepeats,
1044
+ className,
1045
+ children,
1046
+ role = "status",
1047
+ style,
1048
+ "aria-label": ariaLabel,
1049
+ ...props
1050
+ }) {
1051
+ const reduced = usePrefersReducedMotion();
1052
+ const hasLabel = React2.Children.count(children) > 0;
1053
+ const classes = [
1054
+ "eth-motion-attention-pulse",
1055
+ `eth-motion-attention-pulse--${severity}`,
1056
+ reduced ? "eth-motion-reduced" : null,
1057
+ className
1058
+ ].filter(Boolean).join(" ");
1059
+ const attentionStyle = {
1060
+ "--eth-motion-attention-color": severityColor(severity),
1061
+ "--eth-motion-attention-border": severityBorderColor(severity),
1062
+ "--eth-motion-attention-ink": severityInkColor(severity),
1063
+ "--eth-motion-attention-repeat": String(maxRepeats ?? "infinite"),
1064
+ ...style
1065
+ };
1066
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
1067
+ "span",
1068
+ {
1069
+ ...props,
1070
+ "aria-label": ariaLabel ?? (hasLabel ? void 0 : "Attention required"),
1071
+ className: classes,
1072
+ "data-eth-component": "AttentionPulse",
1073
+ role,
1074
+ style: attentionStyle,
1075
+ children: [
1076
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MotionStyles, {}),
1077
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "eth-motion-attention-pulse__marker", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "eth-motion-attention-pulse__dot", children: "!" }) }),
1078
+ hasLabel ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "eth-motion-attention-pulse__label", children }) : null
1079
+ ]
1080
+ }
1081
+ );
1082
+ }
1083
+ function severityBorderColor(severity) {
1084
+ return severity === "warning" ? "#8a6a00" : severityColor(severity);
1085
+ }
1086
+ function severityInkColor(severity) {
1087
+ return severity === "warning" ? "#161616" : "#ffffff";
1088
+ }
1089
+
1090
+ // src/components/DAGStatusTransition.tsx
1091
+ var React3 = __toESM(require("react"), 1);
1092
+ var import_jsx_runtime4 = require("react/jsx-runtime");
1093
+ function DAGStatusTransition({
1094
+ nodes,
1095
+ previousNodes,
1096
+ edges = [],
1097
+ className,
1098
+ ...props
1099
+ }) {
1100
+ const reduced = usePrefersReducedMotion();
1101
+ const previousStatus = new Map(previousNodes?.map((node) => [node.id, node.status]) ?? []);
1102
+ const positions = layoutDag(nodes, edges);
1103
+ const frame = viewBoxFor(nodes, positions);
1104
+ const titleId = React3.useId();
1105
+ const descriptionId = React3.useId();
1106
+ const markerBaseId = React3.useId();
1107
+ const changedCount = nodes.filter(
1108
+ (node) => previousStatus.has(node.id) && previousStatus.get(node.id) !== node.status
1109
+ ).length;
1110
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1111
+ "section",
1112
+ {
1113
+ ...props,
1114
+ className: `eth-motion-dag-status ${reduced ? "eth-motion-reduced" : ""} ${className ?? ""}`,
1115
+ "data-eth-component": "DAGStatusTransition",
1116
+ "aria-label": "DAG status transition",
1117
+ children: [
1118
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(MotionStyles, {}),
1119
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1120
+ "svg",
1121
+ {
1122
+ className: "eth-motion-dag-status__svg",
1123
+ viewBox: frame.viewBox,
1124
+ width: frame.width,
1125
+ height: frame.height,
1126
+ role: "img",
1127
+ "aria-labelledby": `${titleId} ${descriptionId}`,
1128
+ children: [
1129
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("title", { id: titleId, children: "DAG status transition" }),
1130
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("desc", { id: descriptionId, children: `${nodes.length} nodes, ${edges.length} edges, ${changedCount} changed node statuses.` }),
1131
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("defs", { children: edges.map((edge, index) => {
1132
+ const to = positions.get(edge.to);
1133
+ if (!to) return null;
1134
+ const color = edgeColor(edge, nodes.find((node) => node.id === edge.to)?.status);
1135
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1136
+ "marker",
1137
+ {
1138
+ id: markerIdFromUseId(markerBaseId, index),
1139
+ markerWidth: "8",
1140
+ markerHeight: "8",
1141
+ refX: "7",
1142
+ refY: "3",
1143
+ orient: "auto",
1144
+ markerUnits: "strokeWidth",
1145
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M0,0 L0,6 L7,3 z", fill: color })
1146
+ },
1147
+ `${edge.from}-${edge.to}-${index}`
1148
+ );
1149
+ }) }),
1150
+ edges.map((edge, index) => {
1151
+ const from = positions.get(edge.from);
1152
+ const to = positions.get(edge.to);
1153
+ if (!from || !to) return null;
1154
+ const color = edgeColor(edge, nodes.find((node) => node.id === edge.to)?.status);
1155
+ const active = edge.active && !reduced;
1156
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1157
+ "path",
1158
+ {
1159
+ className: "eth-motion-dag-status__edge",
1160
+ d: edgePath(from, to),
1161
+ fill: "none",
1162
+ stroke: color,
1163
+ strokeWidth: active ? 2 : 1.25,
1164
+ strokeDasharray: active ? "6 6" : void 0,
1165
+ markerEnd: `url(#${markerIdFromUseId(markerBaseId, index)})`,
1166
+ style: active ? { animation: "eth-motion-flow-dash 900ms linear infinite" } : void 0
1167
+ },
1168
+ `${edge.from}-${edge.to}-${index}`
1169
+ );
1170
+ }),
1171
+ nodes.map((node) => {
1172
+ const point = positions.get(node.id);
1173
+ if (!point) return null;
1174
+ const previous = previousStatus.get(node.id);
1175
+ const changed = previous !== void 0 && previous !== node.status;
1176
+ const statusText = changed ? `${compactLabelForStatus(previous)} -> ${compactLabelForStatus(node.status)}` : labelForStatus(node.status);
1177
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1178
+ "g",
1179
+ {
1180
+ className: `eth-motion-dag-status__node ${changed ? "eth-motion-dag-status__node--changed" : ""}`,
1181
+ transform: `translate(${point.x}, ${point.y})`,
1182
+ children: [
1183
+ changed ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1184
+ "rect",
1185
+ {
1186
+ className: "eth-motion-dag-status__change-ring",
1187
+ x: -NODE_WIDTH / 2 - 4,
1188
+ y: -NODE_HEIGHT / 2 - 4,
1189
+ width: NODE_WIDTH + 8,
1190
+ height: NODE_HEIGHT + 8,
1191
+ rx: 0,
1192
+ fill: "none",
1193
+ stroke: statusColor(node.status)
1194
+ }
1195
+ ) : null,
1196
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1197
+ "rect",
1198
+ {
1199
+ className: "eth-motion-dag-status__card",
1200
+ x: -NODE_WIDTH / 2,
1201
+ y: -NODE_HEIGHT / 2,
1202
+ width: NODE_WIDTH,
1203
+ height: NODE_HEIGHT,
1204
+ rx: 0,
1205
+ fill: "var(--cds-layer-02, #ffffff)",
1206
+ stroke: "var(--cds-border-subtle, #e0e0e0)"
1207
+ }
1208
+ ),
1209
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1210
+ "rect",
1211
+ {
1212
+ x: -NODE_WIDTH / 2,
1213
+ y: -NODE_HEIGHT / 2,
1214
+ width: 4,
1215
+ height: NODE_HEIGHT,
1216
+ rx: 0,
1217
+ fill: statusColor(node.status)
1218
+ }
1219
+ ),
1220
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("circle", { cx: -NODE_WIDTH / 2 + 20, cy: -9, r: 4.5, fill: statusColor(node.status) }),
1221
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("text", { className: "eth-motion-dag-status__label", x: -NODE_WIDTH / 2 + 34, y: -7, children: truncate(node.label, 18) }),
1222
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("text", { className: "eth-motion-dag-status__status", x: -NODE_WIDTH / 2 + 34, y: 15, children: truncate(statusText, 24) }),
1223
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("title", { children: changed && previous ? `${node.label}: ${labelForStatus(previous)} to ${labelForStatus(node.status)}` : `${node.label}: ${labelForStatus(node.status)}` })
1224
+ ]
1225
+ },
1226
+ node.id
1227
+ );
1228
+ })
1229
+ ]
1230
+ }
1231
+ ),
1232
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("ol", { className: "eth-motion-dag-status__fallback", children: nodes.map((node) => {
1233
+ const previous = previousStatus.get(node.id);
1234
+ const changed = previous !== void 0 && previous !== node.status;
1235
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("li", { children: changed && previous ? `${node.label}: ${labelForStatus(previous)} to ${labelForStatus(node.status)}` : `${node.label}: ${labelForStatus(node.status)}` }, node.id);
1236
+ }) })
1237
+ ]
1238
+ }
1239
+ );
1240
+ }
1241
+ var NODE_WIDTH = 160;
1242
+ var NODE_HEIGHT = 64;
1243
+ var NODE_GAP_X = 190;
1244
+ var NODE_GAP_Y = 92;
1245
+ function layoutDag(nodes, edges = []) {
1246
+ const map = /* @__PURE__ */ new Map();
1247
+ const ids = new Set(nodes.map((node) => node.id));
1248
+ const ranks = new Map(nodes.map((node) => [node.id, 0]));
1249
+ const validEdges = edges.filter((edge) => ids.has(edge.from) && ids.has(edge.to));
1250
+ for (let pass = 0; pass < nodes.length; pass += 1) {
1251
+ for (const edge of validEdges) {
1252
+ const fromRank = ranks.get(edge.from) ?? 0;
1253
+ const toRank = ranks.get(edge.to) ?? 0;
1254
+ if (toRank < fromRank + 1) ranks.set(edge.to, fromRank + 1);
1255
+ }
1256
+ }
1257
+ const groups = /* @__PURE__ */ new Map();
1258
+ for (const node of nodes) {
1259
+ const rank = ranks.get(node.id) ?? 0;
1260
+ groups.set(rank, [...groups.get(rank) ?? [], node]);
1261
+ }
1262
+ const maxRows = Math.max(1, ...Array.from(groups.values()).map((group) => group.length));
1263
+ nodes.forEach((node, index) => {
1264
+ const rank = ranks.get(node.id) ?? index;
1265
+ const group = groups.get(rank) ?? [node];
1266
+ const rowIndex = Math.max(
1267
+ 0,
1268
+ group.findIndex((candidate) => candidate.id === node.id)
1269
+ );
1270
+ const row = group.length === 1 && maxRows > 1 ? (maxRows - 1) / 2 : rowIndex;
1271
+ map.set(node.id, {
1272
+ x: node.x ?? 88 + rank * NODE_GAP_X,
1273
+ y: node.y ?? 64 + row * NODE_GAP_Y
1274
+ });
1275
+ });
1276
+ return map;
1277
+ }
1278
+ function viewBoxFor(nodes, positions) {
1279
+ if (!nodes.length) {
1280
+ return { viewBox: "0 0 320 120", width: 320, height: 120 };
1281
+ }
1282
+ const points = nodes.map((node) => positions.get(node.id)).filter((point) => Boolean(point));
1283
+ const minX = Math.floor(Math.min(...points.map((point) => point.x)) - NODE_WIDTH / 2 - 24);
1284
+ const minY = Math.floor(Math.min(...points.map((point) => point.y)) - NODE_HEIGHT / 2 - 20);
1285
+ const maxX = Math.ceil(Math.max(...points.map((point) => point.x)) + NODE_WIDTH / 2 + 30);
1286
+ const maxY = Math.ceil(Math.max(...points.map((point) => point.y)) + NODE_HEIGHT / 2 + 20);
1287
+ const width = maxX - minX;
1288
+ const height = maxY - minY;
1289
+ return { viewBox: `${minX} ${minY} ${width} ${height}`, width, height };
1290
+ }
1291
+ function edgePath(from, to) {
1292
+ const horizontal = Math.abs(to.x - from.x) >= Math.abs(to.y - from.y);
1293
+ if (horizontal) {
1294
+ const direction2 = to.x >= from.x ? 1 : -1;
1295
+ const start2 = { x: from.x + NODE_WIDTH / 2 * direction2, y: from.y };
1296
+ const end2 = { x: to.x - NODE_WIDTH / 2 * direction2, y: to.y };
1297
+ const controlOffset2 = Math.max(32, Math.abs(end2.x - start2.x) * 0.5);
1298
+ return `M ${start2.x} ${start2.y} C ${start2.x + controlOffset2 * direction2} ${start2.y}, ${end2.x - controlOffset2 * direction2} ${end2.y}, ${end2.x} ${end2.y}`;
1299
+ }
1300
+ const direction = to.y >= from.y ? 1 : -1;
1301
+ const start = { x: from.x, y: from.y + NODE_HEIGHT / 2 * direction };
1302
+ const end = { x: to.x, y: to.y - NODE_HEIGHT / 2 * direction };
1303
+ const controlOffset = Math.max(28, Math.abs(end.y - start.y) * 0.5);
1304
+ return `M ${start.x} ${start.y} C ${start.x} ${start.y + controlOffset * direction}, ${end.x} ${end.y - controlOffset * direction}, ${end.x} ${end.y}`;
1305
+ }
1306
+ function edgeColor(edge, toStatus) {
1307
+ if (edge.status) return statusColor(edge.status);
1308
+ if (edge.active) return "var(--cds-interactive, #0f62fe)";
1309
+ if (toStatus === "failed" || toStatus === "blocked") return statusColor(toStatus);
1310
+ return "var(--cds-border-strong, #8d8d8d)";
1311
+ }
1312
+ function markerIdFromUseId(id, index) {
1313
+ return `eth-motion-dag-arrow-${id.replace(/[^a-zA-Z0-9_-]/g, "")}-${index}`;
1314
+ }
1315
+ function labelForStatus(status) {
1316
+ switch (status) {
1317
+ case "approval-required":
1318
+ return "Approval required";
1319
+ case "pending-approval":
1320
+ return "Pending approval";
1321
+ case "in-progress":
1322
+ return "In progress";
1323
+ case "not-started":
1324
+ return "Not started";
1325
+ default:
1326
+ return status.split("-").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
1327
+ }
1328
+ }
1329
+ function compactLabelForStatus(status) {
1330
+ switch (status) {
1331
+ case "approval-required":
1332
+ return "Approval";
1333
+ case "pending-approval":
1334
+ return "Pending";
1335
+ case "in-progress":
1336
+ return "Progress";
1337
+ case "not-started":
1338
+ return "Not started";
1339
+ default:
1340
+ return labelForStatus(status);
1341
+ }
1342
+ }
1343
+ function truncate(value, maxLength) {
1344
+ if (value.length <= maxLength) return value;
1345
+ return `${value.slice(0, Math.max(0, maxLength - 3))}...`;
1346
+ }
1347
+
1348
+ // src/components/DocumentLockPulse.tsx
1349
+ var import_jsx_runtime5 = require("react/jsx-runtime");
1350
+ function DocumentLockPulse({
1351
+ lockedBy,
1352
+ active = true,
1353
+ className,
1354
+ children,
1355
+ role = "status",
1356
+ style,
1357
+ "aria-label": ariaLabel,
1358
+ ...props
1359
+ }) {
1360
+ const reduced = usePrefersReducedMotion();
1361
+ const owner = children ?? lockedBy ?? "Document locked";
1362
+ const ownerLabel = plainText(children ?? lockedBy);
1363
+ const classes = [
1364
+ "eth-motion-document-lock",
1365
+ active ? "eth-motion-document-lock--active" : "eth-motion-document-lock--idle",
1366
+ reduced ? "eth-motion-reduced" : void 0,
1367
+ className
1368
+ ].filter(Boolean).join(" ");
1369
+ const defaultLabel = ownerLabel ? `Document lock ${active ? "active" : "held"} by ${ownerLabel}` : active ? "Document lock active" : "Document locked";
1370
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1371
+ "span",
1372
+ {
1373
+ ...props,
1374
+ "aria-label": ariaLabel ?? defaultLabel,
1375
+ className: classes,
1376
+ "data-eth-component": "DocumentLockPulse",
1377
+ role,
1378
+ style,
1379
+ children: [
1380
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(MotionStyles, {}),
1381
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "eth-motion-document-lock__indicator", "aria-hidden": "true", children: [
1382
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "eth-motion-document-lock__pulse" }),
1383
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(LockGlyph, { className: "eth-motion-document-lock__icon" })
1384
+ ] }),
1385
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "eth-motion-document-lock__content", children: [
1386
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "eth-motion-document-lock__state", children: active ? "Active edit" : "Lock held" }),
1387
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "eth-motion-document-lock__owner", children: owner })
1388
+ ] })
1389
+ ]
1390
+ }
1391
+ );
1392
+ }
1393
+ function LockGlyph(props) {
1394
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { ...props, "aria-hidden": "true", focusable: "false", viewBox: "0 0 16 16", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1395
+ "path",
1396
+ {
1397
+ d: "M5 7V5a3 3 0 0 1 6 0v2h1a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V8a1 1 0 0 1 1-1h1Zm1.5 0h3V5a1.5 1.5 0 0 0-3 0v2Z",
1398
+ fill: "currentColor"
1399
+ }
1400
+ ) });
1401
+ }
1402
+ function plainText(value) {
1403
+ if (typeof value === "string" || typeof value === "number") {
1404
+ return String(value);
1405
+ }
1406
+ return void 0;
1407
+ }
1408
+
1409
+ // src/components/PipelineFlowAnimation.tsx
1410
+ var React4 = __toESM(require("react"), 1);
1411
+ var import_jsx_runtime6 = require("react/jsx-runtime");
1412
+ function PipelineFlowAnimation({
1413
+ nodes,
1414
+ edges,
1415
+ className,
1416
+ "aria-label": ariaLabel = "Pipeline flow",
1417
+ ...props
1418
+ }) {
1419
+ const reduced = usePrefersReducedMotion();
1420
+ const positions = layoutNodes(nodes);
1421
+ const frame = viewBoxFor2(nodes, positions);
1422
+ const titleId = React4.useId();
1423
+ const descriptionId = React4.useId();
1424
+ const markerBaseId = React4.useId();
1425
+ const activeNodeIds = new Set(
1426
+ edges.filter((edge) => edge.active).flatMap((edge) => [edge.from, edge.to]).concat(nodes.filter((node) => isActiveStatus(node.status)).map((node) => node.id))
1427
+ );
1428
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1429
+ "section",
1430
+ {
1431
+ ...props,
1432
+ className: `eth-motion-pipeline-flow ${reduced ? "eth-motion-reduced" : ""} ${className ?? ""}`,
1433
+ "data-eth-component": "PipelineFlowAnimation",
1434
+ "aria-label": ariaLabel,
1435
+ children: [
1436
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MotionStyles, {}),
1437
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1438
+ "svg",
1439
+ {
1440
+ className: "eth-motion-pipeline-flow__svg",
1441
+ viewBox: frame.viewBox,
1442
+ width: frame.width,
1443
+ height: frame.height,
1444
+ role: "img",
1445
+ "aria-labelledby": `${titleId} ${descriptionId}`,
1446
+ children: [
1447
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("title", { id: titleId, children: "Pipeline flow" }),
1448
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("desc", { id: descriptionId, children: nodes.length ? `${nodes.length} stages and ${edges.length} handoffs. ${nodes.map((node) => `${node.label}: ${labelForStatus2(node.status)}`).join(", ")}.` : "No pipeline stages." }),
1449
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("defs", { children: edges.map((edge, index) => {
1450
+ const toNode = nodes.find((node) => node.id === edge.to);
1451
+ const color = edgeColor2(edge, toNode?.status);
1452
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1453
+ "marker",
1454
+ {
1455
+ id: markerIdFromUseId2(markerBaseId, index),
1456
+ markerWidth: "7",
1457
+ markerHeight: "7",
1458
+ refX: "6",
1459
+ refY: "3.5",
1460
+ orient: "auto",
1461
+ markerUnits: "strokeWidth",
1462
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M0,0 L0,7 L7,3.5 z", fill: color })
1463
+ },
1464
+ `${edge.from}-${edge.to}-${index}`
1465
+ );
1466
+ }) }),
1467
+ edges.map((edge, index) => {
1468
+ const from = positions.get(edge.from);
1469
+ const to = positions.get(edge.to);
1470
+ if (!from || !to) return null;
1471
+ const toNode = nodes.find((node) => node.id === edge.to);
1472
+ const color = edgeColor2(edge, toNode?.status);
1473
+ const active = Boolean(edge.active);
1474
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1475
+ "path",
1476
+ {
1477
+ className: "eth-motion-pipeline-flow__edge",
1478
+ d: edgePath2(from, to),
1479
+ fill: "none",
1480
+ markerEnd: `url(#${markerIdFromUseId2(markerBaseId, index)})`,
1481
+ stroke: color,
1482
+ strokeWidth: active ? 2.5 : 1.5,
1483
+ strokeDasharray: active ? "7 7" : void 0,
1484
+ style: active && !reduced ? { animation: "eth-motion-flow-dash 900ms linear infinite" } : void 0
1485
+ },
1486
+ `${edge.from}-${edge.to}-${index}`
1487
+ );
1488
+ }),
1489
+ !nodes.length ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("text", { className: "eth-motion-pipeline-flow__empty", x: "16", y: "52", children: "No pipeline stages" }) : null,
1490
+ nodes.map((node) => {
1491
+ const point = positions.get(node.id);
1492
+ if (!point) return null;
1493
+ const active = activeNodeIds.has(node.id);
1494
+ const cardX = -NODE_WIDTH2 / 2;
1495
+ const cardY = -NODE_HEIGHT2 / 2;
1496
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1497
+ "g",
1498
+ {
1499
+ className: `eth-motion-pipeline-flow__node ${active ? "eth-motion-pipeline-flow__node--active" : ""}`,
1500
+ transform: `translate(${point.x}, ${point.y})`,
1501
+ children: [
1502
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1503
+ "rect",
1504
+ {
1505
+ className: "eth-motion-pipeline-flow__card",
1506
+ x: cardX,
1507
+ y: cardY,
1508
+ width: NODE_WIDTH2,
1509
+ height: NODE_HEIGHT2,
1510
+ rx: 0
1511
+ }
1512
+ ),
1513
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1514
+ "rect",
1515
+ {
1516
+ className: "eth-motion-pipeline-flow__stripe",
1517
+ x: cardX,
1518
+ y: cardY,
1519
+ width: 4,
1520
+ height: NODE_HEIGHT2,
1521
+ rx: 0,
1522
+ fill: statusColor(node.status)
1523
+ }
1524
+ ),
1525
+ active && !reduced ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1526
+ "circle",
1527
+ {
1528
+ className: "eth-motion-pipeline-flow__pulse",
1529
+ cx: cardX + 22,
1530
+ cy: cardY + 20,
1531
+ r: 9,
1532
+ fill: "none",
1533
+ stroke: statusColor(node.status)
1534
+ }
1535
+ ) : null,
1536
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1537
+ "circle",
1538
+ {
1539
+ className: "eth-motion-pipeline-flow__dot",
1540
+ cx: cardX + 22,
1541
+ cy: cardY + 20,
1542
+ r: 5,
1543
+ fill: statusColor(node.status)
1544
+ }
1545
+ ),
1546
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("text", { className: "eth-motion-pipeline-flow__label", x: cardX + 36, y: cardY + 24, children: truncate2(node.label, 15) }),
1547
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("text", { className: "eth-motion-pipeline-flow__status", x: cardX + 14, y: cardY + 48, children: truncate2(labelForStatus2(node.status), 20) }),
1548
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("title", { children: `${node.label}: ${labelForStatus2(node.status)}` })
1549
+ ]
1550
+ },
1551
+ node.id
1552
+ );
1553
+ })
1554
+ ]
1555
+ }
1556
+ ),
1557
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("ol", { className: "eth-motion-pipeline-flow__fallback", children: nodes.map((node) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("li", { children: [
1558
+ node.label,
1559
+ ": ",
1560
+ labelForStatus2(node.status)
1561
+ ] }, node.id)) })
1562
+ ]
1563
+ }
1564
+ );
1565
+ }
1566
+ var NODE_WIDTH2 = 144;
1567
+ var NODE_HEIGHT2 = 64;
1568
+ var NODE_GAP_X2 = 188;
1569
+ function layoutNodes(nodes) {
1570
+ const map = /* @__PURE__ */ new Map();
1571
+ nodes.forEach((node, index) => {
1572
+ map.set(node.id, {
1573
+ x: node.x ?? NODE_WIDTH2 / 2 + 20 + NODE_GAP_X2 * index,
1574
+ y: node.y ?? NODE_HEIGHT2 / 2 + 18
1575
+ });
1576
+ });
1577
+ return map;
1578
+ }
1579
+ function viewBoxFor2(nodes, positions) {
1580
+ if (!nodes.length) {
1581
+ return { viewBox: "0 0 320 96", width: 320, height: 96 };
1582
+ }
1583
+ const points = nodes.map((node) => positions.get(node.id)).filter((point) => Boolean(point));
1584
+ const minX = Math.floor(Math.min(...points.map((point) => point.x)) - NODE_WIDTH2 / 2 - 18);
1585
+ const minY = Math.floor(Math.min(...points.map((point) => point.y)) - NODE_HEIGHT2 / 2 - 16);
1586
+ const maxX = Math.ceil(Math.max(...points.map((point) => point.x)) + NODE_WIDTH2 / 2 + 26);
1587
+ const maxY = Math.ceil(Math.max(...points.map((point) => point.y)) + NODE_HEIGHT2 / 2 + 16);
1588
+ const width = maxX - minX;
1589
+ const height = maxY - minY;
1590
+ return { viewBox: `${minX} ${minY} ${width} ${height}`, width, height };
1591
+ }
1592
+ function edgePath2(from, to) {
1593
+ const direction = to.x >= from.x ? 1 : -1;
1594
+ const start = { x: from.x + NODE_WIDTH2 / 2 * direction, y: from.y };
1595
+ const end = { x: to.x - NODE_WIDTH2 / 2 * direction, y: to.y };
1596
+ const controlOffset = Math.max(26, Math.abs(end.x - start.x) * 0.5);
1597
+ return `M ${start.x} ${start.y} C ${start.x + controlOffset * direction} ${start.y}, ${end.x - controlOffset * direction} ${end.y}, ${end.x} ${end.y}`;
1598
+ }
1599
+ function edgeColor2(edge, toStatus) {
1600
+ if (edge.status) return statusColor(edge.status);
1601
+ if (edge.active) return "var(--cds-interactive, #0f62fe)";
1602
+ if (toStatus === "failed" || toStatus === "blocked") return statusColor(toStatus);
1603
+ return "var(--cds-border-strong, #8d8d8d)";
1604
+ }
1605
+ function markerIdFromUseId2(id, index) {
1606
+ return `eth-motion-pipeline-arrow-${id.replace(/[^a-zA-Z0-9_-]/g, "")}-${index}`;
1607
+ }
1608
+ function isActiveStatus(status) {
1609
+ return status === "running" || status === "in-progress" || status === "active";
1610
+ }
1611
+ function labelForStatus2(status) {
1612
+ switch (status) {
1613
+ case "approval-required":
1614
+ return "Approval required";
1615
+ case "pending-approval":
1616
+ return "Pending approval";
1617
+ case "in-progress":
1618
+ return "In progress";
1619
+ case "not-started":
1620
+ return "Not started";
1621
+ default:
1622
+ return status.split("-").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
1623
+ }
1624
+ }
1625
+ function truncate2(value, maxLength) {
1626
+ if (value.length <= maxLength) return value;
1627
+ return `${value.slice(0, Math.max(0, maxLength - 3))}...`;
1628
+ }
1629
+
1630
+ // src/components/ProgressTransition.tsx
1631
+ var React5 = __toESM(require("react"), 1);
1632
+ var import_jsx_runtime7 = require("react/jsx-runtime");
1633
+ function ProgressTransition({
1634
+ from,
1635
+ to,
1636
+ durationMs = 320,
1637
+ children,
1638
+ className,
1639
+ ...props
1640
+ }) {
1641
+ const reduced = usePrefersReducedMotion();
1642
+ const [current, setCurrent] = React5.useState(from ?? to);
1643
+ React5.useEffect(() => {
1644
+ if (reduced || durationMs <= 0 || typeof window === "undefined") {
1645
+ setCurrent(to);
1646
+ return;
1647
+ }
1648
+ const startValue = from ?? current;
1649
+ const delta = to - startValue;
1650
+ const startedAt = performance.now();
1651
+ let frame = 0;
1652
+ const tick = (now) => {
1653
+ const progress = Math.min(1, (now - startedAt) / durationMs);
1654
+ const eased = 1 - Math.pow(1 - progress, 3);
1655
+ setCurrent(startValue + delta * eased);
1656
+ if (progress < 1) frame = window.requestAnimationFrame(tick);
1657
+ };
1658
+ frame = window.requestAnimationFrame(tick);
1659
+ return () => window.cancelAnimationFrame(frame);
1660
+ }, [to, from, durationMs, reduced]);
1661
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1662
+ "section",
1663
+ {
1664
+ ...props,
1665
+ className: `eth-motion-progress-transition ${reduced ? "eth-motion-reduced" : ""} ${className ?? ""}`,
1666
+ "data-eth-component": "ProgressTransition",
1667
+ children: [
1668
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(MotionStyles, {}),
1669
+ children ? children(current) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("progress", { value: current, max: 100, "aria-label": "Progress", children: [
1670
+ Math.round(current),
1671
+ "%"
1672
+ ] })
1673
+ ]
1674
+ }
1675
+ );
1676
+ }
1677
+
1678
+ // src/components/SkeletonLoadingPattern.tsx
1679
+ var import_jsx_runtime8 = require("react/jsx-runtime");
1680
+ var articleLineWidths = ["96%", "88%", "100%", "92%", "76%", "84%", "68%", "80%"];
1681
+ var listLineWidths = ["76%", "88%", "64%", "82%", "70%", "90%"];
1682
+ var tableCellWidths = ["72%", "92%", "58%", "84%", "66%", "78%"];
1683
+ function SkeletonLoadingPattern({
1684
+ columns = 4,
1685
+ label = "Loading content",
1686
+ lines = 3,
1687
+ rows,
1688
+ variant = "article",
1689
+ className,
1690
+ style,
1691
+ role = "status",
1692
+ "aria-busy": ariaBusy = true,
1693
+ "aria-label": ariaLabel,
1694
+ ...props
1695
+ }) {
1696
+ const reduced = usePrefersReducedMotion();
1697
+ const pattern = normalizePattern(variant);
1698
+ const lineCount = clampCount(lines, 1, 8);
1699
+ const rowCount = clampCount(rows ?? (pattern === "table" ? 4 : 3), 1, 8);
1700
+ const columnCount = clampCount(columns, 2, 6);
1701
+ const classes = [
1702
+ "eth-motion-skeleton-loading",
1703
+ `eth-motion-skeleton-loading--${pattern}`,
1704
+ reduced ? "eth-motion-reduced" : void 0,
1705
+ className
1706
+ ].filter(Boolean).join(" ");
1707
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1708
+ "section",
1709
+ {
1710
+ ...props,
1711
+ "aria-busy": ariaBusy,
1712
+ "aria-label": ariaLabel ?? label,
1713
+ className: classes,
1714
+ "data-eth-component": "SkeletonLoadingPattern",
1715
+ "data-pattern": pattern,
1716
+ role,
1717
+ style,
1718
+ children: [
1719
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(MotionStyles, {}),
1720
+ renderPattern(pattern, lineCount, rowCount, columnCount)
1721
+ ]
1722
+ }
1723
+ );
1724
+ }
1725
+ function renderPattern(pattern, lines, rows, columns) {
1726
+ switch (pattern) {
1727
+ case "card":
1728
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CardPattern, { lines });
1729
+ case "list":
1730
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ListPattern, { rows });
1731
+ case "table":
1732
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(TablePattern, { columns, rows });
1733
+ case "article":
1734
+ default:
1735
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ArticlePattern, { lines });
1736
+ }
1737
+ }
1738
+ function ArticlePattern({ lines }) {
1739
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1740
+ "div",
1741
+ {
1742
+ "aria-hidden": "true",
1743
+ className: "eth-motion-skeleton-loading__surface eth-motion-skeleton-loading__surface--article",
1744
+ children: [
1745
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "eth-motion-skeleton-loading__article-header", children: [
1746
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1747
+ SkeletonBlock,
1748
+ {
1749
+ className: "eth-motion-skeleton-loading__block--eyebrow",
1750
+ segment: "eyebrow",
1751
+ style: { inlineSize: "7rem" }
1752
+ }
1753
+ ),
1754
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1755
+ SkeletonBlock,
1756
+ {
1757
+ className: "eth-motion-skeleton-loading__block--title",
1758
+ segment: "title",
1759
+ style: { inlineSize: "min(22rem, 74%)" }
1760
+ }
1761
+ )
1762
+ ] }),
1763
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "eth-motion-skeleton-loading__article-body", children: Array.from({ length: lines }).map((_, index) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1764
+ SkeletonBlock,
1765
+ {
1766
+ className: "eth-motion-skeleton-loading__block--line",
1767
+ segment: "text-line",
1768
+ style: { inlineSize: articleLineWidths[index % articleLineWidths.length] }
1769
+ },
1770
+ index
1771
+ )) })
1772
+ ]
1773
+ }
1774
+ );
1775
+ }
1776
+ function CardPattern({ lines }) {
1777
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1778
+ "div",
1779
+ {
1780
+ "aria-hidden": "true",
1781
+ className: "eth-motion-skeleton-loading__surface eth-motion-skeleton-loading__surface--card",
1782
+ children: [
1783
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SkeletonBlock, { className: "eth-motion-skeleton-loading__block--media", segment: "media" }),
1784
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "eth-motion-skeleton-loading__card-body", children: [
1785
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1786
+ SkeletonBlock,
1787
+ {
1788
+ className: "eth-motion-skeleton-loading__block--title",
1789
+ segment: "title",
1790
+ style: { inlineSize: "78%" }
1791
+ }
1792
+ ),
1793
+ Array.from({ length: lines }).map((_, index) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1794
+ SkeletonBlock,
1795
+ {
1796
+ className: "eth-motion-skeleton-loading__block--line",
1797
+ segment: "text-line",
1798
+ style: { inlineSize: articleLineWidths[(index + 2) % articleLineWidths.length] }
1799
+ },
1800
+ index
1801
+ ))
1802
+ ] }),
1803
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "eth-motion-skeleton-loading__card-metrics", children: Array.from({ length: 3 }).map((_, index) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1804
+ SkeletonBlock,
1805
+ {
1806
+ className: "eth-motion-skeleton-loading__block--metric",
1807
+ segment: "metric"
1808
+ },
1809
+ index
1810
+ )) })
1811
+ ]
1812
+ }
1813
+ );
1814
+ }
1815
+ function ListPattern({ rows }) {
1816
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1817
+ "div",
1818
+ {
1819
+ "aria-hidden": "true",
1820
+ className: "eth-motion-skeleton-loading__surface eth-motion-skeleton-loading__surface--list",
1821
+ children: Array.from({ length: rows }).map((_, index) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1822
+ "div",
1823
+ {
1824
+ className: "eth-motion-skeleton-loading__list-row",
1825
+ "data-skeleton-row": "list",
1826
+ children: [
1827
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SkeletonBlock, { className: "eth-motion-skeleton-loading__block--avatar", segment: "avatar" }),
1828
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "eth-motion-skeleton-loading__list-copy", children: [
1829
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1830
+ SkeletonBlock,
1831
+ {
1832
+ className: "eth-motion-skeleton-loading__block--line",
1833
+ segment: "text-line",
1834
+ style: { inlineSize: listLineWidths[index % listLineWidths.length] }
1835
+ }
1836
+ ),
1837
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1838
+ SkeletonBlock,
1839
+ {
1840
+ className: "eth-motion-skeleton-loading__block--caption",
1841
+ segment: "caption",
1842
+ style: { inlineSize: listLineWidths[(index + 2) % listLineWidths.length] }
1843
+ }
1844
+ )
1845
+ ] }),
1846
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1847
+ SkeletonBlock,
1848
+ {
1849
+ className: "eth-motion-skeleton-loading__block--tag",
1850
+ segment: "tag",
1851
+ style: { inlineSize: index % 2 === 0 ? "4.25rem" : "3.25rem" }
1852
+ }
1853
+ )
1854
+ ]
1855
+ },
1856
+ index
1857
+ ))
1858
+ }
1859
+ );
1860
+ }
1861
+ function TablePattern({ columns, rows }) {
1862
+ const gridStyle = { gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))` };
1863
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1864
+ "div",
1865
+ {
1866
+ "aria-hidden": "true",
1867
+ className: "eth-motion-skeleton-loading__surface eth-motion-skeleton-loading__surface--table",
1868
+ children: [
1869
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "eth-motion-skeleton-loading__table-header", style: gridStyle, children: Array.from({ length: columns }).map((_, index) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1870
+ SkeletonBlock,
1871
+ {
1872
+ className: "eth-motion-skeleton-loading__block--column",
1873
+ segment: "column-header",
1874
+ style: { inlineSize: tableCellWidths[(index + 1) % tableCellWidths.length] }
1875
+ },
1876
+ index
1877
+ )) }),
1878
+ Array.from({ length: rows }).map((_, rowIndex) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1879
+ "div",
1880
+ {
1881
+ className: "eth-motion-skeleton-loading__table-row",
1882
+ "data-skeleton-row": "table",
1883
+ style: gridStyle,
1884
+ children: Array.from({ length: columns }).map((_2, columnIndex) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1885
+ SkeletonBlock,
1886
+ {
1887
+ cell: true,
1888
+ className: "eth-motion-skeleton-loading__block--cell",
1889
+ segment: "cell",
1890
+ style: {
1891
+ inlineSize: tableCellWidths[(rowIndex + columnIndex) % tableCellWidths.length]
1892
+ }
1893
+ },
1894
+ columnIndex
1895
+ ))
1896
+ },
1897
+ rowIndex
1898
+ ))
1899
+ ]
1900
+ }
1901
+ );
1902
+ }
1903
+ function SkeletonBlock({
1904
+ cell,
1905
+ className,
1906
+ segment,
1907
+ style
1908
+ }) {
1909
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1910
+ "span",
1911
+ {
1912
+ className: `eth-motion-skeleton-loading__block ${className ?? ""}`,
1913
+ "data-skeleton-cell": cell ? "" : void 0,
1914
+ "data-skeleton-segment": segment,
1915
+ style
1916
+ }
1917
+ );
1918
+ }
1919
+ function clampCount(value, min, max) {
1920
+ if (!Number.isFinite(value)) return min;
1921
+ return Math.min(max, Math.max(min, Math.floor(value)));
1922
+ }
1923
+ function normalizePattern(variant) {
1924
+ if (variant === "card" || variant === "list" || variant === "table") return variant;
1925
+ return "article";
1926
+ }
1927
+
1928
+ // src/components/StatusChangeAnimation.tsx
1929
+ var import_jsx_runtime9 = require("react/jsx-runtime");
1930
+ function StatusChangeAnimation({
1931
+ status,
1932
+ previousStatus,
1933
+ label,
1934
+ className,
1935
+ children,
1936
+ style,
1937
+ "aria-label": ariaLabel,
1938
+ "aria-labelledby": ariaLabelledBy,
1939
+ ...props
1940
+ }) {
1941
+ const reduced = usePrefersReducedMotion();
1942
+ const changed = previousStatus !== void 0 && previousStatus !== status;
1943
+ const statusLabel = formatStatusLabel(status);
1944
+ const previousStatusLabel = previousStatus ? formatStatusLabel(previousStatus) : void 0;
1945
+ const displayLabel = children ?? label ?? "Status";
1946
+ const announcementLabel = textFromNode(label) ?? textFromNode(children) ?? "Status";
1947
+ const announcement = changed && previousStatusLabel ? `${announcementLabel} changed from ${previousStatusLabel} to ${statusLabel}` : `${announcementLabel} is ${statusLabel}`;
1948
+ const rootClassName = [
1949
+ "eth-motion-status-change",
1950
+ `eth-motion-status-change--${status}`,
1951
+ changed ? "eth-motion-status-change--changed" : null,
1952
+ reduced ? "eth-motion-reduced" : null,
1953
+ className
1954
+ ].filter(Boolean).join(" ");
1955
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1956
+ "span",
1957
+ {
1958
+ ...props,
1959
+ "aria-atomic": "true",
1960
+ "aria-label": ariaLabel ?? (ariaLabelledBy ? void 0 : announcement),
1961
+ "aria-labelledby": ariaLabelledBy,
1962
+ className: rootClassName,
1963
+ "data-current-status": status,
1964
+ "data-eth-component": "StatusChangeAnimation",
1965
+ "data-previous-status": previousStatus,
1966
+ role: "status",
1967
+ style: {
1968
+ "--eth-motion-status-color": statusColor(status),
1969
+ "--eth-motion-status-previous-color": previousStatus ? statusColor(previousStatus) : statusColor(status),
1970
+ ...style
1971
+ },
1972
+ children: [
1973
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(MotionStyles, {}),
1974
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "eth-motion-status-change__indicator", "aria-hidden": "true", children: [
1975
+ changed ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "eth-motion-status-change__previous-dot" }) : null,
1976
+ changed ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "eth-motion-status-change__connector" }) : null,
1977
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "eth-motion-status-change__current-dot" })
1978
+ ] }),
1979
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: "eth-motion-status-change__content", children: [
1980
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "eth-motion-status-change__label", children: displayLabel }),
1981
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "eth-motion-status-change__state", children: changed && previousStatusLabel ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
1982
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "eth-motion-status-change__previous", children: previousStatusLabel }),
1983
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "eth-motion-status-change__separator", children: "to" }),
1984
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "eth-motion-status-change__current", children: statusLabel })
1985
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "eth-motion-status-change__current", children: statusLabel }) })
1986
+ ] })
1987
+ ]
1988
+ }
1989
+ );
1990
+ }
1991
+ function formatStatusLabel(status) {
1992
+ return status.split("-").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
1993
+ }
1994
+ function textFromNode(node) {
1995
+ if (typeof node === "string" || typeof node === "number") return String(node);
1996
+ return void 0;
1997
+ }
1998
+
1999
+ // src/components/StepCompletionAnimation.tsx
2000
+ var import_jsx_runtime10 = require("react/jsx-runtime");
2001
+ var stateLabels = {
2002
+ completed: "Completed",
2003
+ current: "In progress",
2004
+ pending: "Pending"
2005
+ };
2006
+ function StepCompletionAnimation({
2007
+ completed = true,
2008
+ description,
2009
+ label = "Step completed",
2010
+ state,
2011
+ className,
2012
+ children,
2013
+ role = "status",
2014
+ "aria-live": ariaLive = "polite",
2015
+ ...props
2016
+ }) {
2017
+ const reduced = usePrefersReducedMotion();
2018
+ const resolvedState = state ?? (completed ? "completed" : "pending");
2019
+ const stateLabel = stateLabels[resolvedState];
2020
+ const stepClassName = [
2021
+ "eth-motion-step-completion",
2022
+ `eth-motion-step-completion--${resolvedState}`,
2023
+ reduced ? "eth-motion-reduced" : void 0,
2024
+ className
2025
+ ].filter(Boolean).join(" ");
2026
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
2027
+ "span",
2028
+ {
2029
+ ...props,
2030
+ "aria-live": ariaLive,
2031
+ className: stepClassName,
2032
+ "data-eth-component": "StepCompletionAnimation",
2033
+ "data-state": resolvedState,
2034
+ role,
2035
+ children: [
2036
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(MotionStyles, {}),
2037
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "eth-motion-step-completion__marker", "aria-hidden": "true", children: resolvedState === "completed" ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2038
+ "svg",
2039
+ {
2040
+ className: "eth-motion-step-completion__check",
2041
+ focusable: "false",
2042
+ height: "16",
2043
+ viewBox: "0 0 16 16",
2044
+ width: "16",
2045
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
2046
+ "path",
2047
+ {
2048
+ className: "eth-motion-step-completion__check-path",
2049
+ d: "M3.5 8.4 6.5 11.4 12.8 4.6"
2050
+ }
2051
+ )
2052
+ }
2053
+ ) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "eth-motion-step-completion__dot" }) }),
2054
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "eth-motion-step-completion__content", children: children ?? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
2055
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "eth-motion-step-completion__label", children: label }),
2056
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "eth-motion-step-completion__state", children: stateLabel }),
2057
+ description ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "eth-motion-step-completion__description", children: description }) : null
2058
+ ] }) })
2059
+ ]
2060
+ }
2061
+ );
2062
+ }
2063
+
2064
+ // src/components/StreamingText.tsx
2065
+ var React6 = __toESM(require("react"), 1);
2066
+ var import_jsx_runtime11 = require("react/jsx-runtime");
2067
+ function StreamingText({
2068
+ text,
2069
+ intervalMs = 18,
2070
+ onDone,
2071
+ className,
2072
+ role = "status",
2073
+ "aria-busy": ariaBusy,
2074
+ "aria-live": ariaLive = "polite",
2075
+ ...props
2076
+ }) {
2077
+ const reduced = usePrefersReducedMotion();
2078
+ const shouldAnimate = !reduced && intervalMs > 0 && text.length > 0;
2079
+ const [visible, setVisible] = React6.useState(shouldAnimate ? "" : text);
2080
+ const [done, setDone] = React6.useState(!shouldAnimate);
2081
+ const onDoneRef = React6.useRef(onDone);
2082
+ React6.useEffect(() => {
2083
+ onDoneRef.current = onDone;
2084
+ }, [onDone]);
2085
+ React6.useEffect(() => {
2086
+ if (!shouldAnimate) {
2087
+ setVisible(text);
2088
+ setDone(true);
2089
+ onDoneRef.current?.();
2090
+ return;
2091
+ }
2092
+ setVisible("");
2093
+ setDone(false);
2094
+ let index = 0;
2095
+ const timer = window.setInterval(() => {
2096
+ index += 1;
2097
+ setVisible(text.slice(0, index));
2098
+ if (index >= text.length) {
2099
+ window.clearInterval(timer);
2100
+ setDone(true);
2101
+ onDoneRef.current?.();
2102
+ }
2103
+ }, intervalMs);
2104
+ return () => window.clearInterval(timer);
2105
+ }, [text, intervalMs, shouldAnimate]);
2106
+ const streaming = shouldAnimate && !done;
2107
+ const classes = [
2108
+ "eth-motion-streaming-text",
2109
+ streaming ? "eth-motion-streaming-text--streaming" : "eth-motion-streaming-text--complete",
2110
+ reduced ? "eth-motion-reduced" : void 0,
2111
+ className
2112
+ ].filter(Boolean).join(" ");
2113
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
2114
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(MotionStyles, {}),
2115
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
2116
+ "span",
2117
+ {
2118
+ ...props,
2119
+ "aria-busy": ariaBusy ?? streaming,
2120
+ "aria-live": ariaLive,
2121
+ className: classes,
2122
+ "data-eth-component": "StreamingText",
2123
+ "data-streaming": streaming ? "true" : "false",
2124
+ role,
2125
+ children: [
2126
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "eth-motion-streaming-text__content", children: visible }),
2127
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { "aria-hidden": "true", className: "eth-motion-streaming-text__cursor" })
2128
+ ]
2129
+ }
2130
+ )
2131
+ ] });
2132
+ }
2133
+
2134
+ // src/components/SyncProgressAnimation.tsx
2135
+ var import_jsx_runtime12 = require("react/jsx-runtime");
2136
+ var statusContent = {
2137
+ syncing: {
2138
+ accent: "#0f62fe",
2139
+ description: "Replicating source updates and applying remote changes.",
2140
+ label: "Syncing",
2141
+ soft: "#edf5ff"
2142
+ },
2143
+ synced: {
2144
+ accent: "#24a148",
2145
+ description: "Replica is current with the source.",
2146
+ label: "Synced",
2147
+ soft: "#defbe6"
2148
+ },
2149
+ paused: {
2150
+ accent: "#8d8d8d",
2151
+ description: "Sync is paused. No changes are being applied.",
2152
+ label: "Paused",
2153
+ soft: "#f4f4f4"
2154
+ },
2155
+ stale: {
2156
+ accent: "#f1c21b",
2157
+ description: "Replica is outside the expected freshness window.",
2158
+ label: "Stale",
2159
+ soft: "#fcf4d6"
2160
+ },
2161
+ failed: {
2162
+ accent: "#da1e28",
2163
+ description: "Sync stopped before completion. Review the connection and retry.",
2164
+ label: "Failed",
2165
+ soft: "#fff1f1"
2166
+ },
2167
+ error: {
2168
+ accent: "#da1e28",
2169
+ description: "Sync stopped before completion. Review the connection and retry.",
2170
+ label: "Needs attention",
2171
+ soft: "#fff1f1"
2172
+ }
2173
+ };
2174
+ function SyncProgressAnimation({
2175
+ children,
2176
+ className,
2177
+ completed,
2178
+ description,
2179
+ label = "Syncing",
2180
+ progress,
2181
+ rate,
2182
+ remaining,
2183
+ role = "status",
2184
+ source,
2185
+ stage,
2186
+ status = "syncing",
2187
+ style,
2188
+ target,
2189
+ total,
2190
+ variant,
2191
+ "aria-busy": ariaBusy,
2192
+ "aria-label": ariaLabel,
2193
+ "aria-live": ariaLive,
2194
+ ...props
2195
+ }) {
2196
+ const reduced = usePrefersReducedMotion();
2197
+ const content = statusContent[status];
2198
+ const progressValue = normalizeProgress(progress ?? progressFromCounts(completed, total, status));
2199
+ const hasProgress = progressValue !== void 0;
2200
+ const progressText = hasProgress ? `${progressValue}% complete` : content.label;
2201
+ const countText = formatCountProgress(completed, total);
2202
+ const descriptionNode = description ?? children ?? content.description;
2203
+ const hasDetailedContent = [
2204
+ description,
2205
+ children,
2206
+ source,
2207
+ target,
2208
+ stage,
2209
+ rate,
2210
+ remaining,
2211
+ completed,
2212
+ total,
2213
+ progress
2214
+ ].some(hasValue);
2215
+ const resolvedVariant = variant ?? (hasDetailedContent ? "detailed" : "compact");
2216
+ const labelText = textFromNode2(label) ?? "Sync";
2217
+ const announcement = [content.label, hasProgress ? progressText : void 0, countText].filter(Boolean).join(", ");
2218
+ const classes = [
2219
+ "eth-motion-sync-progress",
2220
+ `eth-motion-sync-progress--${resolvedVariant}`,
2221
+ `eth-motion-sync-progress--${status}`,
2222
+ reduced ? "eth-motion-reduced" : void 0,
2223
+ className
2224
+ ].filter(Boolean).join(" ");
2225
+ const rootStyle = {
2226
+ "--eth-motion-sync-accent": content.accent,
2227
+ "--eth-motion-sync-accent-soft": content.soft,
2228
+ ...style
2229
+ };
2230
+ const busy = ariaBusy ?? (status === "syncing" ? true : void 0);
2231
+ if (resolvedVariant === "compact") {
2232
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
2233
+ "span",
2234
+ {
2235
+ ...props,
2236
+ "aria-atomic": "true",
2237
+ "aria-busy": busy,
2238
+ "aria-label": ariaLabel ?? `${labelText} ${announcement}`,
2239
+ "aria-live": ariaLive ?? (status === "syncing" ? "polite" : void 0),
2240
+ className: classes,
2241
+ "data-eth-component": "SyncProgressAnimation",
2242
+ "data-sync-progress": progressValue,
2243
+ "data-sync-status": status,
2244
+ role,
2245
+ style: rootStyle,
2246
+ children: [
2247
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(MotionStyles, {}),
2248
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SyncIndicator, { status }),
2249
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "eth-motion-sync-progress__compact-copy", children: [
2250
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "eth-motion-sync-progress__label", children: label }),
2251
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "eth-motion-sync-progress__compact-state", children: hasProgress ? `${progressValue}%` : content.label })
2252
+ ] })
2253
+ ]
2254
+ }
2255
+ );
2256
+ }
2257
+ const metaItems = [
2258
+ { label: "Source", value: source },
2259
+ { label: "Target", value: target },
2260
+ { label: "Rate", value: rate },
2261
+ { label: "Remaining", value: remaining }
2262
+ ].filter((item) => hasValue(item.value));
2263
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
2264
+ "section",
2265
+ {
2266
+ ...props,
2267
+ "aria-atomic": "true",
2268
+ "aria-busy": busy,
2269
+ "aria-label": ariaLabel ?? `${labelText} ${announcement}`,
2270
+ "aria-live": ariaLive ?? (status === "syncing" ? "polite" : void 0),
2271
+ className: classes,
2272
+ "data-eth-component": "SyncProgressAnimation",
2273
+ "data-sync-progress": progressValue,
2274
+ "data-sync-status": status,
2275
+ role,
2276
+ style: rootStyle,
2277
+ children: [
2278
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(MotionStyles, {}),
2279
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SyncIndicator, { status }),
2280
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "eth-motion-sync-progress__body", children: [
2281
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "eth-motion-sync-progress__header", children: [
2282
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "eth-motion-sync-progress__title-group", children: [
2283
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "eth-motion-sync-progress__eyebrow", children: stage ?? "Replication" }),
2284
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "eth-motion-sync-progress__label", children: label })
2285
+ ] }),
2286
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "eth-motion-sync-progress__chip", children: [
2287
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "eth-motion-sync-progress__chip-dot", "aria-hidden": "true" }),
2288
+ content.label
2289
+ ] })
2290
+ ] }),
2291
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "eth-motion-sync-progress__description", children: descriptionNode }),
2292
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "eth-motion-sync-progress__meter", children: [
2293
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2294
+ "div",
2295
+ {
2296
+ "aria-label": "Sync transfer progress",
2297
+ "aria-valuemax": 100,
2298
+ "aria-valuemin": 0,
2299
+ "aria-valuenow": progressValue,
2300
+ "aria-valuetext": hasProgress ? progressText : content.label,
2301
+ className: "eth-motion-sync-progress__track",
2302
+ role: "progressbar",
2303
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
2304
+ "span",
2305
+ {
2306
+ className: `eth-motion-sync-progress__bar ${hasProgress ? "" : "eth-motion-sync-progress__bar--indeterminate"}`,
2307
+ style: hasProgress ? { inlineSize: `${progressValue}%` } : void 0
2308
+ }
2309
+ )
2310
+ }
2311
+ ),
2312
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "eth-motion-sync-progress__progress-copy", children: [hasProgress ? `${progressValue}%` : content.label, countText].filter(Boolean).join(" | ") })
2313
+ ] })
2314
+ ] }),
2315
+ metaItems.length ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("dl", { className: "eth-motion-sync-progress__meta", "aria-label": "Sync metadata", children: metaItems.map((item) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "eth-motion-sync-progress__meta-item", children: [
2316
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("dt", { children: item.label }),
2317
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("dd", { children: item.value })
2318
+ ] }, item.label)) }) : null
2319
+ ]
2320
+ }
2321
+ );
2322
+ }
2323
+ function SyncIndicator({ status }) {
2324
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "eth-motion-sync-progress__indicator", "aria-hidden": "true", children: status === "syncing" ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "eth-motion-sync-progress__spinner" }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "eth-motion-sync-progress__glyph" }) });
2325
+ }
2326
+ function progressFromCounts(completed, total, status) {
2327
+ if (status === "synced") return 100;
2328
+ if (!isFiniteNumber(completed) || !isFiniteNumber(total) || total <= 0) return void 0;
2329
+ return completed / total * 100;
2330
+ }
2331
+ function normalizeProgress(value) {
2332
+ if (!isFiniteNumber(value)) return void 0;
2333
+ return Math.min(100, Math.max(0, Math.round(value)));
2334
+ }
2335
+ function formatCountProgress(completed, total) {
2336
+ if (!isFiniteNumber(completed) || !isFiniteNumber(total) || total <= 0) return void 0;
2337
+ const safeCompleted = Math.max(0, Math.floor(completed));
2338
+ const safeTotal = Math.max(0, Math.floor(total));
2339
+ return `${safeCompleted} of ${safeTotal} items`;
2340
+ }
2341
+ function isFiniteNumber(value) {
2342
+ return typeof value === "number" && Number.isFinite(value);
2343
+ }
2344
+ function hasValue(value) {
2345
+ return value !== void 0 && value !== null && value !== false && value !== "";
2346
+ }
2347
+ function textFromNode2(node) {
2348
+ if (typeof node === "string" || typeof node === "number") return String(node);
2349
+ return void 0;
2350
+ }
2351
+
2352
+ // src/index.tsx
2353
+ var MotionComponentNames = [
2354
+ "ProgressTransition",
2355
+ "PipelineFlowAnimation",
2356
+ "DAGStatusTransition",
2357
+ "AgentThinkingAnimation",
2358
+ "SyncProgressAnimation",
2359
+ "SkeletonLoadingPattern",
2360
+ "AttentionPulse",
2361
+ "DocumentLockPulse",
2362
+ "StreamingText",
2363
+ "StepCompletionAnimation",
2364
+ "StatusChangeAnimation"
2365
+ ];
2366
+ // Annotate the CommonJS export names for ESM import in node:
2367
+ 0 && (module.exports = {
2368
+ AgentThinkingAnimation,
2369
+ AttentionPulse,
2370
+ DAGStatusTransition,
2371
+ DocumentLockPulse,
2372
+ MotionComponentNames,
2373
+ PipelineFlowAnimation,
2374
+ ProgressTransition,
2375
+ SkeletonLoadingPattern,
2376
+ StatusChangeAnimation,
2377
+ StepCompletionAnimation,
2378
+ StreamingText,
2379
+ SyncProgressAnimation
2380
+ });
2381
+ //# sourceMappingURL=index.cjs.map