aegis-swap-widget 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +120 -2
- package/DESIGN.md +77 -0
- package/README.md +249 -4
- package/dist/aegis-swap-widget.js +2295 -2458
- package/dist/components/icons.d.ts +9 -2
- package/dist/core.d.ts +15 -0
- package/dist/core.js +66 -0
- package/dist/errors.d.ts +1 -0
- package/dist/hooks/useChangeEmitter.d.ts +25 -0
- package/dist/hooks/useLifecycleToast.d.ts +16 -0
- package/dist/hooks/usePoolChangeEmitter.d.ts +1 -0
- package/dist/hooks/useResolvedTheme.d.ts +1 -0
- package/dist/hooks/useStatusChangeEmitter.d.ts +2 -0
- package/dist/hooks/useSubmitSwap.d.ts +10 -1
- package/dist/hooks/useTokenAllowance.d.ts +3 -0
- package/dist/hooks/useValueRefresh.d.ts +1 -0
- package/dist/index.d.ts +9 -7
- package/dist/metadata.d.ts +8 -0
- package/dist/permit.d.ts +7 -0
- package/dist/polling-BI4pZg8Z.js +1252 -0
- package/dist/polling.d.ts +1 -0
- package/dist/styles.css +1 -1
- package/dist/swap/authorizePermit.d.ts +30 -0
- package/dist/swap/executeSwapTransaction.d.ts +37 -0
- package/dist/swap/types.d.ts +7 -0
- package/dist/toast/ToastItem.d.ts +33 -0
- package/dist/toast/Toaster.d.ts +31 -0
- package/dist/toast/layout.d.ts +21 -0
- package/dist/toast/state.d.ts +69 -0
- package/dist/toast/swipe.d.ts +23 -0
- package/dist/toast/timer.d.ts +16 -0
- package/dist/toast/toast.d.ts +28 -0
- package/dist/toast/useDocumentVisible.d.ts +6 -0
- package/dist/toast/useToastTimer.d.ts +13 -0
- package/dist/transactionProgress.d.ts +25 -1
- package/dist/widget/AegisDirectSwapWidget.d.ts +17 -1
- package/dist/widget/AmountField.d.ts +4 -1
- package/dist/widget/ExecutionDetails.d.ts +1 -3
- package/dist/widget/NetworkSelector.d.ts +5 -2
- package/dist/widget/ProgressRail.d.ts +23 -0
- package/dist/widget/types.d.ts +81 -18
- package/dist/widget/useSwapController.d.ts +89 -0
- package/dist/widget/viewState.d.ts +1 -0
- package/package.json +7 -2
- package/dist/hooks/useScrollAnchor.d.ts +0 -12
package/CHANGELOG.md
CHANGED
|
@@ -5,7 +5,124 @@ All notable changes to this project are documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
-
## [
|
|
8
|
+
## [0.3.0] - 2026-06-08
|
|
9
|
+
|
|
10
|
+
### Removed (breaking)
|
|
11
|
+
- `targets` prop — use `poolIds` (identical `string[]` shape).
|
|
12
|
+
- `markets` prop — use `pools`; `Object.values(markets)` migrates an existing map.
|
|
13
|
+
- `defaultDirection` values `'intoTarget'` / `'outOfTarget'` — use `'buy'` / `'sell'`.
|
|
14
|
+
|
|
15
|
+
### Changed (breaking)
|
|
16
|
+
- Renamed `showApprovalModeControl` → `showApprovalMode`, pairing it with
|
|
17
|
+
`defaultApprovalMode`.
|
|
18
|
+
|
|
19
|
+
### Migration
|
|
20
|
+
- `targets={ids}` → `poolIds={ids}`
|
|
21
|
+
- `markets={map}` → `pools={Object.values(map)}`
|
|
22
|
+
- `defaultDirection="intoTarget"` → `defaultDirection="buy"`
|
|
23
|
+
- `defaultDirection="outOfTarget"` → `defaultDirection="sell"`
|
|
24
|
+
- `showApprovalModeControl={x}` → `showApprovalMode={x}`
|
|
25
|
+
|
|
26
|
+
### Internal
|
|
27
|
+
- Refactored the widget into a `useSwapController` hook (state, derivation, and
|
|
28
|
+
hook orchestration) over a thin presentational component, decomposed the swap
|
|
29
|
+
money path into pure `src/swap/` modules (`authorizePermit`,
|
|
30
|
+
`executeSwapTransaction`), and unified the host-callback emitters behind a
|
|
31
|
+
single `useChangeEmitter` primitive. No public behavior change.
|
|
32
|
+
|
|
33
|
+
### Added
|
|
34
|
+
- Toast notifications as an alternative transaction-status surface: new
|
|
35
|
+
`statusSurface` prop (`'rail'` default, `'toast'`, `'both'`, `'none'`) plus
|
|
36
|
+
`toastPosition`. One toast per swap attempt morphs loading → success/error in
|
|
37
|
+
place with the received amount and a View transaction action; wallet
|
|
38
|
+
rejections auto-dismiss after 4s, other errors after 8s. The root
|
|
39
|
+
`data-progress-state` attribute stays on for every surface.
|
|
40
|
+
- `AegisSwapToaster` export: the toast viewport as a standalone component.
|
|
41
|
+
Mounting it anywhere takes over rendering from widget-provided toasters —
|
|
42
|
+
exactly one viewport per page — and owns `position`, `theme`/`accentColor`,
|
|
43
|
+
`duration`, `visibleToasts`, `closeButton`, `expand`, and `offset`. Toasts
|
|
44
|
+
stack with depth, expand on hover/focus, swipe-to-dismiss with momentum
|
|
45
|
+
(interruptible CSS transitions throughout), dismiss on Escape when focused,
|
|
46
|
+
pause their timers while hovered, mid-swipe, and in hidden tabs, and reduce
|
|
47
|
+
to fades under `prefers-reduced-motion`. Lifecycle morphs replay quiet icon
|
|
48
|
+
and text entrances in place, and terminal states tint the card border
|
|
49
|
+
(success whisper, error alarm) the way the progress rail recolors. The
|
|
50
|
+
viewport is hardened for arbitrary host pages: host `li`/text styling
|
|
51
|
+
cannot leak in, toasts hide in print, and the light theme keeps icon
|
|
52
|
+
contrast AA without overriding an explicit host accent.
|
|
53
|
+
- `aegisToast` export: toast function for host apps sharing the same viewport —
|
|
54
|
+
`aegisToast()` / `.info` / `.success` / `.error` / `.loading` / `.dismiss` /
|
|
55
|
+
`.promise`, with upsert-by-id morphing. New public types
|
|
56
|
+
`AegisSwapToasterProps`, `AegisSwapStatusSurface`, `AegisToastAction`,
|
|
57
|
+
`AegisToastOptions`, `AegisToastPosition`, `AegisToastType`, and
|
|
58
|
+
`AegisToastPromiseMessage`/`AegisToastPromiseMessages`.
|
|
59
|
+
- `onPoolChange` prop: fires with the active pool id whenever it changes —
|
|
60
|
+
user tab selection or a `poolIds` update that forces a fallback. Silent on
|
|
61
|
+
mount, so hosts only hear genuine transitions.
|
|
62
|
+
- `resolveTokenIconUrl` export (plus the `TokenMetadataByAddress` type): the
|
|
63
|
+
widget's own icon-source order — config `iconUrl`, metadata service, ichi
|
|
64
|
+
naming guess — so hosts rendering their own token marks resolve identically.
|
|
65
|
+
- `onStatusChange` prop: fires a lifecycle snapshot (`status`, `progress`, `txHash`,
|
|
66
|
+
`error`, `label`, rail geometry, and `walletPrompts`) on every transition, mirroring
|
|
67
|
+
the top progress rail — including errors and wallet rejections, which never appear
|
|
68
|
+
as a `status`. `walletPrompts.total/completed/active` exposes the SDK-owned provider
|
|
69
|
+
prompt plan for ERC20 approval, Permit2 authorization, and swap submission.
|
|
70
|
+
- `AegisSwapProgressRail` export: the widget's animated top rail as a standalone
|
|
71
|
+
component hosts can mount on their own containers, themed via `--aegis-swap-accent`,
|
|
72
|
+
`--aegis-swap-danger`, and `--aegis-swap-success` (the rail CSS now carries literal
|
|
73
|
+
dark-theme fallbacks for use outside the widget root).
|
|
74
|
+
- Host-tunable top rail tokens: `--aegis-rail-height`, `--aegis-rail-hold`, and
|
|
75
|
+
`--aegis-rail-fade` via the widget `style` prop. The success auto-reset reads the
|
|
76
|
+
computed hold/fade values so host-tuned terminal animations and status cleanup stay
|
|
77
|
+
synchronized.
|
|
78
|
+
- The top rail now separates completion from activity: `completePct` tracks completed
|
|
79
|
+
wallet-provider prompts, while pending/mining shimmer always sweeps the full top
|
|
80
|
+
border instead of starting from the completed fill.
|
|
81
|
+
- `networkOptions` prop plus `AegisSwapNetworkOption`/`AegisSwapNetworkIcon` types:
|
|
82
|
+
a display-only network menu list for previewing upcoming chains — non-selected
|
|
83
|
+
options render disabled by default with optional `status` text; a list without
|
|
84
|
+
the active chain gets it prepended; switching is not wired yet.
|
|
85
|
+
- Public types `AegisSwapStatusSnapshot`, `AegisSwapWalletPromptProgress`,
|
|
86
|
+
`SubmitStatus`, `TransactionProgressState`, and the `isUserRejectedError` helper.
|
|
87
|
+
|
|
88
|
+
### Changed
|
|
89
|
+
- The branded header (`title`/`subtitle`) is now text-only: the Aegis logomark no longer
|
|
90
|
+
renders next to host-provided titles. Aegis attribution lives solely in the
|
|
91
|
+
"Powered by Aegis" footer.
|
|
92
|
+
- The trade-details toggle no longer compensates ancestor scroll position when
|
|
93
|
+
expanding or collapsing; the panel expands in place.
|
|
94
|
+
- Hover styles apply only on hover-capable devices (`@media (hover: hover)`), so taps
|
|
95
|
+
on touch screens no longer leave stuck hover states (raised tabs, rotated flip arrows).
|
|
96
|
+
- The direction-flip arrows now spin when the direction actually flips (driven by a
|
|
97
|
+
`data-direction` attribute) instead of pre-playing the rotation on hover.
|
|
98
|
+
- A busy CTA reads as working, not blocked: while approving/signing/submitting the
|
|
99
|
+
submit button keeps near-full opacity, shows a `progress` cursor, and runs a soft
|
|
100
|
+
sheen (`data-busy` attribute, motion-gated).
|
|
101
|
+
- Status feedback eases in instead of popping: error/success lines and the explorer
|
|
102
|
+
link get a staggered fade-rise, and the success line opens with a self-drawing
|
|
103
|
+
check ("Swap complete · received ~…", previously an em dash).
|
|
104
|
+
- Network-menu rows cascade in as the menu opens (30ms steps, reduced-motion safe),
|
|
105
|
+
and the menu's overlay shadow is re-tuned for the light theme.
|
|
106
|
+
- Switching feels like one control: the pool tabs and the Exact/Max approval
|
|
107
|
+
segments glide a single active pill between options instead of cross-fading
|
|
108
|
+
two buttons, and the Sell/Buy token pills cross-fade when a switch retargets
|
|
109
|
+
them. New `--aegis-switch-dur`/`--aegis-spring` tokens (overridable via the
|
|
110
|
+
`style` prop) drive it; reduced-motion safe.
|
|
111
|
+
- Concentric corner radii on nested chrome: pool tab rail, network menu, approval
|
|
112
|
+
segments, and the trade-details toggle now derive outer radius = inner + padding.
|
|
113
|
+
- The trade-details panel sheds visual weight: approval segments and route actions
|
|
114
|
+
drop from 40px to 26px (keeping control-height touch targets via invisible
|
|
115
|
+
extensions), the route chip loses its divider hairlines and dead drop shadow, the
|
|
116
|
+
active pill is fill-only, and the setting rows tighten to 38px with unified 12px
|
|
117
|
+
labels.
|
|
118
|
+
|
|
119
|
+
### Fixed
|
|
120
|
+
- Keyboard focus no longer reshapes controls: the global `:focus-visible` rule forced
|
|
121
|
+
a 6px border-radius onto every focused element, visibly squaring the circular flip
|
|
122
|
+
button; the ring now follows each element's own radius.
|
|
123
|
+
- The slippage input no longer triggers iOS Safari's focus auto-zoom (16px input font
|
|
124
|
+
on coarse pointers).
|
|
125
|
+
- The network trigger's touch target is extended to ~44px without growing the chip.
|
|
9
126
|
|
|
10
127
|
## [0.2.0] - 2026-06-05
|
|
11
128
|
|
|
@@ -75,7 +192,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
75
192
|
- Initial embeddable direct-pool Aegis swap widget for WATER, WOOD, GRASS, and STONE.
|
|
76
193
|
- Generic pool widget API; ERC-20 → Permit2 approval and Permit2 batch signing.
|
|
77
194
|
|
|
78
|
-
[Unreleased]: https://github.com/amplifi-liquidity/aegis-widget/compare/v0.
|
|
195
|
+
[Unreleased]: https://github.com/amplifi-liquidity/aegis-widget/compare/v0.3.0...HEAD
|
|
196
|
+
[0.3.0]: https://github.com/amplifi-liquidity/aegis-widget/compare/v0.2.0...v0.3.0
|
|
79
197
|
[0.2.0]: https://github.com/amplifi-liquidity/aegis-widget/compare/v0.1.3...v0.2.0
|
|
80
198
|
[0.1.3]: https://github.com/amplifi-liquidity/aegis-widget/compare/v0.1.2...v0.1.3
|
|
81
199
|
[0.1.2]: https://github.com/amplifi-liquidity/aegis-widget/compare/v0.1.0...v0.1.2
|
package/DESIGN.md
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Design tokens
|
|
2
|
+
|
|
3
|
+
The widget themes through CSS custom properties on the `.aegis-swap-widget` root
|
|
4
|
+
(and the toast viewport). This file is the reference for the **public** tokens —
|
|
5
|
+
the ones a host may override and depend on. Set them inline via the `style` prop,
|
|
6
|
+
in a stylesheet on an ancestor, or per-toaster via `AegisSwapToaster`.
|
|
7
|
+
|
|
8
|
+
Renaming or removing anything in the tables below is a breaking (major) change.
|
|
9
|
+
Tokens prefixed `--aegis-_*` are internal and may change without notice.
|
|
10
|
+
|
|
11
|
+
## Color
|
|
12
|
+
|
|
13
|
+
The default palette is authored in **OKLCH**: neutrals are tinted toward the
|
|
14
|
+
brand hue (~165) so the surface reads as one family, each step's lightness is
|
|
15
|
+
matched to keep text contrast (subtle/muted stay ≥ 4.5:1 on the panel for 12px
|
|
16
|
+
text), and no neutral is pure black or white. Derived accent tints
|
|
17
|
+
(`--aegis-swap-accent-soft/-line/-glow/-ring`) are computed with
|
|
18
|
+
`color-mix(in srgb, …)`, so a host can override `--aegis-swap-accent` with **any**
|
|
19
|
+
CSS color (hex, `rgb()`, `oklch()`, …) and the whole accent system recomputes.
|
|
20
|
+
|
|
21
|
+
| Token | Role |
|
|
22
|
+
| --- | --- |
|
|
23
|
+
| `--aegis-swap-accent` | CTA, selected pool, focus ring, links. Host's primary knob. |
|
|
24
|
+
| `--aegis-swap-accent-text` | Text on the accent CTA. Auto-derived from `accentColor`; override with `accentTextColor`. |
|
|
25
|
+
| `--aegis-swap-success` | Terminal success fill (rail, toast). |
|
|
26
|
+
| `--aegis-swap-danger` | Error fill and inline error text. |
|
|
27
|
+
| `--aegis-swap-bg` / `--aegis-swap-panel` / `--aegis-swap-panel-raised` / `--aegis-swap-panel-soft` | Surface ramp, darkest → most raised. |
|
|
28
|
+
| `--aegis-swap-text` / `--aegis-swap-muted` / `--aegis-swap-subtle` | Text ramp, primary → tertiary. |
|
|
29
|
+
| `--aegis-swap-border` / `--aegis-swap-border-strong` | Hairline and emphasized borders. |
|
|
30
|
+
| `--aegis-swap-font-family` | Font family; the widget does **not** inherit the host font by default. |
|
|
31
|
+
|
|
32
|
+
`theme="light"` swaps the surface/text/border/danger ramp; `accent`/`success`
|
|
33
|
+
carry across both themes. `theme="auto"` follows `prefers-color-scheme`.
|
|
34
|
+
|
|
35
|
+
## Motion
|
|
36
|
+
|
|
37
|
+
All motion is CSS and respects `prefers-reduced-motion` automatically.
|
|
38
|
+
|
|
39
|
+
| Token | Default | Role |
|
|
40
|
+
| --- | --- | --- |
|
|
41
|
+
| `--aegis-switch-dur` | `260ms` | Segmented-pill glide and Sell/Buy token swap. `0ms` disables. |
|
|
42
|
+
| `--aegis-spring` | `cubic-bezier(0.22, 1, 0.36, 1)` | Easing for interactive state changes. |
|
|
43
|
+
| `--aegis-ease` | `cubic-bezier(0.2, 0, 0, 1)` | Easing for entrances and transitions. |
|
|
44
|
+
|
|
45
|
+
The pool-tab/approval-segment open is intentionally slower than the close
|
|
46
|
+
(enter-slow, exit-fast); that asymmetry is by design, not a value to "correct".
|
|
47
|
+
|
|
48
|
+
## Progress rail
|
|
49
|
+
|
|
50
|
+
| Token | Default | Role |
|
|
51
|
+
| --- | --- | --- |
|
|
52
|
+
| `--aegis-rail-height` | `3px` | Rail thickness. |
|
|
53
|
+
| `--aegis-rail-hold` | `3000ms` | How long the terminal state holds before fading. |
|
|
54
|
+
| `--aegis-rail-fade` | `420ms` | Terminal fade-out duration. |
|
|
55
|
+
|
|
56
|
+
`--aegis-rail-hold` / `--aegis-rail-fade` must be CSS time strings (`ms`/`s`):
|
|
57
|
+
the widget reads the computed values at runtime to keep the success auto-reset in
|
|
58
|
+
sync with the host-tuned animation. These also apply to the standalone
|
|
59
|
+
`AegisSwapProgressRail`.
|
|
60
|
+
|
|
61
|
+
## Toasts
|
|
62
|
+
|
|
63
|
+
The toast viewport portals to `document.body`, so widget-root variables do **not**
|
|
64
|
+
reach it — set these on `:root` or pass `AegisSwapToaster` props.
|
|
65
|
+
|
|
66
|
+
| Token | Role |
|
|
67
|
+
| --- | --- |
|
|
68
|
+
| `--aegis-swap-toast-z` | Stacking context for the viewport. |
|
|
69
|
+
| `--aegis-swap-toast-width` | Toast card width. |
|
|
70
|
+
| `--aegis-swap-toast-offset-x` / `--aegis-swap-toast-offset-y` | Viewport inset from the chosen corner. |
|
|
71
|
+
|
|
72
|
+
## Internal tokens
|
|
73
|
+
|
|
74
|
+
`--aegis-r-sm/-md/-lg` (radii), `--aegis-seg-*` (segment chrome),
|
|
75
|
+
`--aegis-swap-shell`, and any `--aegis-_*` primitive are internal implementation
|
|
76
|
+
details. They are not part of the supported theming surface and may change
|
|
77
|
+
between minor versions.
|
package/README.md
CHANGED
|
@@ -19,6 +19,9 @@ bundled config sets one; today only Ethereum mainnet is bundled.
|
|
|
19
19
|
npm install aegis-swap-widget
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
+
Peer dependencies (provided by the host app): `react >=18 <20`, `react-dom >=18 <20`,
|
|
23
|
+
and `viem ^2`. The package is ESM-only and ships no runtime dependencies of its own.
|
|
24
|
+
|
|
22
25
|
## Basic Usage
|
|
23
26
|
|
|
24
27
|
```tsx
|
|
@@ -39,6 +42,32 @@ Token icons are hydrated from the same metadata table used by the Aegis website:
|
|
|
39
42
|
`GlobalToken.iconURL` from the Aegis metadata GraphQL API. The default endpoint is
|
|
40
43
|
`https://aegis.markets/graphql/meta`.
|
|
41
44
|
|
|
45
|
+
## Headless Core
|
|
46
|
+
|
|
47
|
+
Use the root import for the React widget and CSS. Use the `/core` entry when a
|
|
48
|
+
host, backend-backed client, or future query layer needs the swap primitives
|
|
49
|
+
without importing the widget UI:
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
import {
|
|
53
|
+
AEGIS_SWAP_MARKETS,
|
|
54
|
+
createSwapPublicClient,
|
|
55
|
+
fetchDirectSwapQuote,
|
|
56
|
+
} from 'aegis-swap-widget/core'
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
The core entry exports chain and pool config helpers, quote fetching, calldata
|
|
60
|
+
encoding, Permit2 helpers, wallet/provider utilities, metadata fetchers, and the
|
|
61
|
+
pure transaction-progress helpers. It does not import the React widget or the
|
|
62
|
+
package stylesheet.
|
|
63
|
+
|
|
64
|
+
To render token icons with the widget's exact resolution order (config
|
|
65
|
+
`iconUrl` → metadata endpoint → ICHI guess), use `resolveTokenIconUrl`:
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
import { resolveTokenIconUrl, fetchGlobalTokenMetadata } from 'aegis-swap-widget/core'
|
|
69
|
+
```
|
|
70
|
+
|
|
42
71
|
## Appearance
|
|
43
72
|
|
|
44
73
|
Hosts can choose the widget surface and brand accent at instantiation time:
|
|
@@ -55,6 +84,10 @@ Hosts can choose the widget surface and brand accent at instantiation time:
|
|
|
55
84
|
|
|
56
85
|
The default accent is neutral green. Pass `accentColor`, `accentTextColor`, `title`, `subtitle`, `className`, or `style` when the widget should blend into another product UI.
|
|
57
86
|
|
|
87
|
+
The default palette is authored in OKLCH (tinted neutrals, a calmer accent). The
|
|
88
|
+
full set of host-overridable CSS variables — color, motion, rail, and toast
|
|
89
|
+
tokens — is documented in [DESIGN.md](./DESIGN.md).
|
|
90
|
+
|
|
58
91
|
## Configure Pools
|
|
59
92
|
|
|
60
93
|
Pass the direct pools you want to expose. This is the recommended integration path because it is not tied to any specific asset list.
|
|
@@ -272,6 +305,214 @@ Use `className` for host CSS selectors and `style` for one-off layout overrides
|
|
|
272
305
|
|
|
273
306
|
`accentColor`, `accentTextColor`, `title`, and `subtitle` are the intended props for making the widget fit a host surface without forking the component.
|
|
274
307
|
|
|
308
|
+
## Transaction Status
|
|
309
|
+
|
|
310
|
+
The widget paints swap progress on a rail along its own top edge — an accent
|
|
311
|
+
sweep while pending/mining, solid green on success, solid red on errors
|
|
312
|
+
(including wallet rejections), then a short hold and fade. The rail is the
|
|
313
|
+
default of two built-in status surfaces; `statusSurface` switches to toast
|
|
314
|
+
notifications, shows `'both'`, or `'none'` (see Toasts below). Hosts can tune
|
|
315
|
+
the rail through the widget's `style` prop:
|
|
316
|
+
|
|
317
|
+
```tsx
|
|
318
|
+
<AegisSwapWidget
|
|
319
|
+
style={{
|
|
320
|
+
'--aegis-rail-height': '4px',
|
|
321
|
+
'--aegis-rail-hold': '1800ms',
|
|
322
|
+
'--aegis-rail-fade': '260ms'
|
|
323
|
+
}}
|
|
324
|
+
/>
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
Use CSS time strings (`ms` or `s`) for `--aegis-rail-hold` and
|
|
328
|
+
`--aegis-rail-fade`; the widget reads the computed tokens at runtime so the
|
|
329
|
+
success auto-reset stays in sync with the host-tuned animation. Hosts can
|
|
330
|
+
mirror that state outside the widget three ways:
|
|
331
|
+
|
|
332
|
+
`onStatusChange` fires a snapshot on every lifecycle transition. `walletPrompts`
|
|
333
|
+
is the SDK-owned provider-prompt plan: ERC20 approval, Permit2 authorization,
|
|
334
|
+
and swap submission are counted from the current allowance/authorization reads.
|
|
335
|
+
Use that for step copy or external rails instead of guessing from status names:
|
|
336
|
+
|
|
337
|
+
```tsx
|
|
338
|
+
<AegisSwapWidget
|
|
339
|
+
onStatusChange={({ status, progress, walletPrompts, txHash, error }) => {
|
|
340
|
+
// status: 'idle' | 'approving' | 'signing' | 'submitting' | 'success'
|
|
341
|
+
// progress: 'pending' | 'mining' | 'success' | 'error' | null (rail hidden)
|
|
342
|
+
// walletPrompts: { total, completed, active } // active is 1-based or null
|
|
343
|
+
// error: user-facing message, e.g. "Request rejected."
|
|
344
|
+
}}
|
|
345
|
+
/>
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
The rail separates step completion from activity: `completePct` fills the calm
|
|
349
|
+
completed portion (for example 33.3% after one of three wallet prompts), while
|
|
350
|
+
the pending/mining shimmer is always a full-width top-border sweep.
|
|
351
|
+
|
|
352
|
+
Errors never appear in `status` (the submit machine resets to `'idle'`); read
|
|
353
|
+
them from `progress === 'error'` plus `error`. For classifying the raw `Error`
|
|
354
|
+
from `onError`, `isUserRejectedError` is exported.
|
|
355
|
+
|
|
356
|
+
Success clears itself after confirming (by default a 3s hold plus the 420ms
|
|
357
|
+
rail fade-out), the widget resets and emits a final
|
|
358
|
+
`{ status: 'idle', progress: null }` snapshot. Errors persist until the
|
|
359
|
+
user interacts with the widget again — the in-widget rail fades out visually,
|
|
360
|
+
but the last snapshot and `data-progress-state` keep reporting `'error'`,
|
|
361
|
+
matching the widget's own inline error message.
|
|
362
|
+
|
|
363
|
+
`AegisSwapProgressRail` renders the animated rail standalone — mount it inside
|
|
364
|
+
any `position: relative` container and feed it the snapshot's `progress`:
|
|
365
|
+
|
|
366
|
+
```tsx
|
|
367
|
+
import { useState } from 'react'
|
|
368
|
+
import {
|
|
369
|
+
AegisSwapProgressRail,
|
|
370
|
+
AegisSwapWidget,
|
|
371
|
+
type AegisSwapStatusSnapshot
|
|
372
|
+
} from 'aegis-swap-widget'
|
|
373
|
+
import 'aegis-swap-widget/styles.css'
|
|
374
|
+
|
|
375
|
+
export function CheckoutHeader() {
|
|
376
|
+
const [status, setStatus] = useState<AegisSwapStatusSnapshot | null>(null)
|
|
377
|
+
|
|
378
|
+
return (
|
|
379
|
+
<>
|
|
380
|
+
<AegisSwapWidget onStatusChange={setStatus} />
|
|
381
|
+
|
|
382
|
+
<header style={{ position: 'relative' }}>
|
|
383
|
+
<AegisSwapProgressRail
|
|
384
|
+
state={status?.progress ?? null}
|
|
385
|
+
label={status?.label ?? undefined}
|
|
386
|
+
completePct={status?.completePct ?? undefined}
|
|
387
|
+
activeWidthPct={status?.activeWidthPct ?? undefined}
|
|
388
|
+
/>
|
|
389
|
+
My checkout
|
|
390
|
+
</header>
|
|
391
|
+
</>
|
|
392
|
+
)
|
|
393
|
+
}
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
Driven from `progress` alone, the standalone rail uses simplified geometry — a
|
|
397
|
+
full-width sweep while in flight, solid fill when terminal. Feed the snapshot's
|
|
398
|
+
`completePct` and `activeWidthPct` to mirror the in-widget prompt-aware fill.
|
|
399
|
+
Theme it by setting `--aegis-swap-accent` (plus
|
|
400
|
+
`--aegis-swap-danger` and `--aegis-swap-success` for the terminal fills) on an
|
|
401
|
+
ancestor. `--aegis-rail-height`, `--aegis-rail-hold`, and
|
|
402
|
+
`--aegis-rail-fade` apply to the standalone rail as CSS too; only the in-widget
|
|
403
|
+
auto-reset timer reads those motion tokens. The built-in color fallbacks are
|
|
404
|
+
the dark-theme values, so light hosts should set them.
|
|
405
|
+
|
|
406
|
+
For CSS-only hooks, the widget root mirrors the rail as
|
|
407
|
+
`data-progress-state="pending | mining | success | error"`, so a host
|
|
408
|
+
stylesheet can react without JavaScript. The attribute stays on for every
|
|
409
|
+
`statusSurface`, including `'toast'` and `'none'`.
|
|
410
|
+
|
|
411
|
+
## Toasts
|
|
412
|
+
|
|
413
|
+
`statusSurface="toast"` replaces the rail with toast notifications; `'both'`
|
|
414
|
+
shows rail and toasts, `'none'` neither. With `'toast'` or `'both'` the widget
|
|
415
|
+
provides its own toast viewport — no extra setup:
|
|
416
|
+
|
|
417
|
+
```tsx
|
|
418
|
+
<AegisSwapWidget statusSurface="toast" toastPosition="bottom-right" />
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
One toast per swap attempt morphs through the lifecycle: a loading card
|
|
422
|
+
follows the same wallet-prompt copy as the rail, then settles into success
|
|
423
|
+
(received amount plus a View transaction link) or error in place. Wallet
|
|
424
|
+
rejections auto-dismiss after 4s and other errors after 8s — the widget's
|
|
425
|
+
inline error message and `data-progress-state` persist regardless. A retry
|
|
426
|
+
withdraws the previous attempt's toast and starts a fresh one.
|
|
427
|
+
|
|
428
|
+
Mounting `<AegisSwapToaster />` anywhere in the app takes over rendering from
|
|
429
|
+
every widget-provided toaster — exactly one toast viewport exists per page —
|
|
430
|
+
which is how hosts control placement and toast options:
|
|
431
|
+
|
|
432
|
+
```tsx
|
|
433
|
+
import { AegisSwapToaster, AegisSwapWidget } from 'aegis-swap-widget'
|
|
434
|
+
import 'aegis-swap-widget/styles.css'
|
|
435
|
+
|
|
436
|
+
<AegisSwapWidget statusSurface="toast" />
|
|
437
|
+
<AegisSwapToaster position="top-right" theme="light" accentColor="#006adc" closeButton />
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
`AegisSwapToaster` props: `position` (`top`/`bottom` × `left`/`center`/`right`,
|
|
441
|
+
default `'bottom-right'`), `theme`/`accentColor`/`accentTextColor` (the toaster
|
|
442
|
+
portals to `document.body`, so widget-root accent variables do not reach it —
|
|
443
|
+
pass these props or set `--aegis-swap-accent` and friends on `:root`),
|
|
444
|
+
`duration` (auto-dismiss for info/success, default 5000ms), `visibleToasts`
|
|
445
|
+
(default 3), `closeButton` (default `false` — swipe and auto-dismiss always
|
|
446
|
+
work), `expand` (always-expanded list instead of the hover-expanded stack),
|
|
447
|
+
`offset` (viewport inset, default 24px / 16px on small screens), `className`,
|
|
448
|
+
and `style` (e.g. `'--aegis-swap-toast-z'`, `'--aegis-swap-toast-width'`).
|
|
449
|
+
|
|
450
|
+
The toast system is the widget's own implementation, not a dependency: toasts
|
|
451
|
+
stack with depth, hovering (or focusing) the stack expands it into a list,
|
|
452
|
+
swiping toward the nearest viewport edge dismisses (momentum-based — a quick
|
|
453
|
+
flick is enough), auto-dismiss timers pause while hovered, while swiping, and
|
|
454
|
+
in hidden tabs, and `prefers-reduced-motion` reduces all motion to fades.
|
|
455
|
+
|
|
456
|
+
`aegisToast` is exported so host apps can fire their own toasts through the
|
|
457
|
+
same viewport — a plain function, no hooks or context:
|
|
458
|
+
|
|
459
|
+
```tsx
|
|
460
|
+
import { aegisToast } from 'aegis-swap-widget'
|
|
461
|
+
|
|
462
|
+
aegisToast('Copied') // info
|
|
463
|
+
aegisToast.success('Saved', { description: 'Order #1204' })
|
|
464
|
+
aegisToast.error('Could not save', { duration: 8000 })
|
|
465
|
+
|
|
466
|
+
const id = aegisToast.loading('Uploading…') // sticky until updated
|
|
467
|
+
aegisToast.success('Uploaded', { id }) // reusing an id morphs in place
|
|
468
|
+
|
|
469
|
+
aegisToast.promise(save(), {
|
|
470
|
+
loading: 'Saving…',
|
|
471
|
+
success: (result) => `Saved ${result.name}`,
|
|
472
|
+
error: (reason) => (reason instanceof Error ? reason.message : 'Save failed')
|
|
473
|
+
})
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
Every creator returns the toast id. Actions render as a new-tab link
|
|
477
|
+
(`{ label, href }`) or a button (`{ label, onClick }`); acting on a toast
|
|
478
|
+
dismisses it. `duration: Infinity` keeps a toast until dismissed;
|
|
479
|
+
`dismissible: false` hides the close affordance and blocks swiping. One caveat
|
|
480
|
+
shared with every module-store toast library: two bundled copies of the
|
|
481
|
+
package keep two independent toast stores (and two viewports).
|
|
482
|
+
|
|
483
|
+
## Motion
|
|
484
|
+
|
|
485
|
+
Switching pools or the approval mode glides a single active pill between the
|
|
486
|
+
options (iOS-segmented-control style), and the Sell/Buy token pills cross-fade
|
|
487
|
+
when a switch retargets them. It is all CSS — no animation library — and every
|
|
488
|
+
animation respects `prefers-reduced-motion` automatically.
|
|
489
|
+
|
|
490
|
+
Hosts tune or disable the switch motion through CSS tokens on the `style` prop:
|
|
491
|
+
|
|
492
|
+
```tsx
|
|
493
|
+
<AegisSwapWidget
|
|
494
|
+
style={{
|
|
495
|
+
'--aegis-switch-dur': '180ms', // pill glide + token swap; '0ms' disables
|
|
496
|
+
'--aegis-spring': 'cubic-bezier(0.2, 0, 0, 1)' // switch easing
|
|
497
|
+
}}
|
|
498
|
+
/>
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
## Migrating to 0.3.0
|
|
502
|
+
|
|
503
|
+
0.3.0 removes the props that were deprecated in 0.2.x. The replacements are
|
|
504
|
+
drop-in:
|
|
505
|
+
|
|
506
|
+
| Removed | Use instead |
|
|
507
|
+
| --- | --- |
|
|
508
|
+
| `targets={[...]}` | `poolIds={[...]}` (same `string[]`) |
|
|
509
|
+
| `markets={map}` | `pools={Object.values(map)}` |
|
|
510
|
+
| `defaultDirection="intoTarget"` | `defaultDirection="buy"` |
|
|
511
|
+
| `defaultDirection="outOfTarget"` | `defaultDirection="sell"` |
|
|
512
|
+
| `showApprovalModeControl` | `showApprovalMode` |
|
|
513
|
+
|
|
514
|
+
No other props changed. See the [CHANGELOG](./CHANGELOG.md) for the full entry.
|
|
515
|
+
|
|
275
516
|
## Props
|
|
276
517
|
|
|
277
518
|
- `provider`: optional EIP-1193 provider. Defaults to auto-detected `window.ethereum`.
|
|
@@ -282,13 +523,15 @@ Use `className` for host CSS selectors and `style` for one-off layout overrides
|
|
|
282
523
|
- `onSuccess`: `({ hash, explorerUrl, swap? })` fired when the receipt confirms.
|
|
283
524
|
- `onError`: `(error)` fired on approval/swap failures (after the widget shows its own message).
|
|
284
525
|
- `onQuote`: `(quote)` fired on every quote refresh.
|
|
526
|
+
- `onStatusChange`: `(snapshot)` fired on every lifecycle transition with what the top progress rail shows (see Transaction Status).
|
|
527
|
+
- `onPoolChange`: `(poolId)` fired when the active pool changes — user selection or a `poolIds` update that forces a fallback. Silent on mount.
|
|
285
528
|
- `chainId`: active chain id. Defaults to Ethereum mainnet.
|
|
286
529
|
- `chains`: optional chain config overrides or additional chain configs, including per-chain `v4Contracts`.
|
|
530
|
+
- `networkOptions`: optional display-only entries for the network menu (`{ id, name, icon?, selected?, disabled?, status? }`). The active entry is resolved by explicit `selected: true`, else by `id` matching the active chain id, else by `name`; a list without the active chain gets it prepended so the trigger never misreports the chain in use. Non-selected options render disabled by default with optional `status` text (e.g. "Coming soon"); `icon` is `'ethereum' | 'base'`. Clicking the enabled option only closes the menu (disabled options ignore clicks) — switching is not wired yet.
|
|
287
531
|
- `pools`: direct pool configs to render and swap against. This is the canonical config path.
|
|
288
532
|
- `defaultPoolId`: initial pool id when `pools` is provided.
|
|
289
533
|
- `poolIds`: optional pool id order/subset. Use this when the host wants to hide pools or control ordering.
|
|
290
|
-
- `defaultDirection`: `buy` (counter token into the pool token) or `sell
|
|
291
|
-
- `markets`: **deprecated** advanced override; pass `pools` (or `Object.values(markets)`) instead.
|
|
534
|
+
- `defaultDirection`: `buy` (counter token into the pool token) or `sell` (pool token into the counter token). Defaults to `buy`.
|
|
292
535
|
- `defaultSlippagePercent`: number (canonical) or numeric string, in percent. Defaults to `1`.
|
|
293
536
|
- `rpcUrls`: RPC fallback list for the active chain, or a `{ [chainId]: string[] }` map for multichain hosts.
|
|
294
537
|
- `metadataEndpoint`: optional metadata GraphQL endpoint for `GlobalToken.iconURL` token icons. Set to `null` to disable.
|
|
@@ -302,9 +545,11 @@ Use `className` for host CSS selectors and `style` for one-off layout overrides
|
|
|
302
545
|
- `accentTextColor`: optional CTA text color for contrast with the chosen accent.
|
|
303
546
|
- `showPoolLink`: whether to render the direct-pool link when the active chain provides `poolExplorerUrl`.
|
|
304
547
|
- `defaultApprovalMode`: `exact` approves only the current quote spend by default; `max` opts into the old unlimited ERC-20 to Permit2 approval behavior.
|
|
305
|
-
- `
|
|
548
|
+
- `showApprovalMode`: whether the details drawer exposes the Exact/Max approval toggle. Defaults to `true`.
|
|
306
549
|
- `showExecutionDetails`: whether to render the collapsible settings drawer for slippage, approval mode, and route. Defaults to `true`.
|
|
307
550
|
- `defaultExecutionDetailsOpen`: whether that settings drawer starts expanded. Defaults to `false`.
|
|
551
|
+
- `statusSurface`: where transaction status is surfaced — `'rail'` (default), `'toast'`, `'both'`, or `'none'`. The root `data-progress-state` attribute stays on regardless (see Toasts).
|
|
552
|
+
- `toastPosition`: viewport corner for the widget-provided toaster. Defaults to `'bottom-right'`; ignored once a host mounts `<AegisSwapToaster />`.
|
|
308
553
|
|
|
309
554
|
The widget intentionally does not inherit the host font; set the
|
|
310
555
|
`--aegis-swap-font-family` CSS variable (via `style` or a stylesheet) to match
|
|
@@ -365,7 +610,7 @@ git switch main && git pull
|
|
|
365
610
|
npm ci
|
|
366
611
|
npm run typecheck && npm run test && npm run build
|
|
367
612
|
# Move CHANGELOG [Unreleased] entries under the new version heading.
|
|
368
|
-
npm version
|
|
613
|
+
npm version minor # e.g. 0.2.1 -> 0.3.0 for a breaking 0.x release; commits and tags vX.Y.Z
|
|
369
614
|
git push origin main --follow-tags
|
|
370
615
|
npm publish --access public # prepublishOnly gate + prepack build run automatically
|
|
371
616
|
npm view aegis-swap-widget version
|