@ikonai/sdk-react-ui 1.7.0 → 1.10.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ikonai/sdk-react-ui",
3
- "version": "1.7.0",
3
+ "version": "1.10.0",
4
4
  "type": "module",
5
5
  "main": "./index.js",
6
6
  "types": "./index.d.ts",
@@ -1,6 +1,6 @@
1
1
  import { IkonClient } from '../sdk/sdk/src/index.ts';
2
2
  import { IkonUiStoreEntry } from './surface';
3
- import { UiComponentLibrary } from './renderer';
3
+ import { DispatchActionOptions, UiComponentLibrary } from './renderer';
4
4
  /**
5
5
  * Mounts a named Parallax sub-tree into a host-controlled container.
6
6
  *
@@ -22,6 +22,6 @@ export interface ParallaxViewProps {
22
22
  /** Connected Ikon client; required for media-bearing UIs (video, audio). */
23
23
  client?: IkonClient | null;
24
24
  /** Optional handler for ParallaxView-internal action dispatches. */
25
- onAction?: (actionId: string, payload?: string) => void;
25
+ onAction?: (actionId: string, payload?: string, options?: DispatchActionOptions) => void;
26
26
  }
27
27
  export declare function ParallaxView({ mount, stores, registry, client, onAction }: ParallaxViewProps): import("react").JSX.Element;
@@ -3,4 +3,4 @@ export { UiComponentRegistry, createComponentLibrary, } from './component-librar
3
3
  export { useUiStore } from './use-ui-store';
4
4
  export { useUiNode } from './use-ui-node';
5
5
  export { useRootView } from './use-root-view';
6
- export type { UiComponentRenderer, UiComponentLibrary, UiNode, UiRenderContext, UiComponentRendererProps, ParsedUiUpdate, UiSnapshot, UiFullSnapshot, UiDiffSnapshot, UiNodeDiff, TextDelta, UiNodeProps, UiUpdateType, UiStoreSnapshot, } from './types';
6
+ export type { DispatchActionOptions, UiComponentRenderer, UiComponentLibrary, UiNode, UiRenderContext, UiComponentRendererProps, ParsedUiUpdate, UiSnapshot, UiFullSnapshot, UiDiffSnapshot, UiNodeDiff, TextDelta, UiNodeProps, UiUpdateType, UiStoreSnapshot, } from './types';
@@ -3,6 +3,17 @@ import { HandlerCache, UiNode, UiStreamStore } from '../../sdk/sdk-ui/src/index.
3
3
  import { IkonClient, IkonVideoPlayback } from '../../sdk/sdk/src/index.ts';
4
4
  import { ComponentType, ReactNode } from 'react';
5
5
  export { type UiUpdateType, type UiNodeProps, type UiNode, type UiNodeDiff, type UiSnapshot, type UiFullSnapshot, type UiDiffSnapshot, type UiSnapshotMetadata, type TextDelta, type ParsedUiUpdate, type UiStoreSnapshot, } from '../../sdk/sdk-ui/src/index.ts';
6
+ /** How a dispatched action should be treated when the server cannot run it. */
7
+ export interface DispatchActionOptions {
8
+ /**
9
+ * The dispatch is the component's own bookkeeping rather than something a person did, so a
10
+ * server refusal is not worth a person's attention. A controlled overlay reports itself closed
11
+ * as it unmounts; when the whole subtree is being removed the server has already retired that
12
+ * action, and the refusal that comes back describes a state it reached on its own. Failures of
13
+ * a best-effort dispatch are logged at debug instead of error.
14
+ */
15
+ bestEffort?: boolean;
16
+ }
6
17
  /**
7
18
  * Context for rendering UI nodes.
8
19
  * Provides access to payloads, action dispatch, and rendering utilities.
@@ -15,7 +26,7 @@ export interface UiRenderContext {
15
26
  /** Render a view by ID */
16
27
  renderView: (viewId: string) => ReactNode;
17
28
  /** Dispatch an action with optional payload */
18
- dispatchAction: (actionId: string, payload?: unknown) => void;
29
+ dispatchAction: (actionId: string, payload?: unknown, options?: DispatchActionOptions) => void;
19
30
  /** The Ikon client instance */
20
31
  client?: IkonClient | null;
21
32
  /** Video playback API */
@@ -1,7 +1,7 @@
1
1
  import { IkonClient, IkonVideoPlayback } from '../../sdk/sdk/src/index.ts';
2
2
  import { UiStreamStore } from '../../sdk/sdk-ui/src/index.ts';
3
3
  import { ReactNode } from 'react';
4
- import { UiComponentLibrary, UiNode, UiRenderContext } from './types';
4
+ import { DispatchActionOptions, UiComponentLibrary, UiNode, UiRenderContext } from './types';
5
5
  /**
6
6
  * Render children nodes by their IDs.
7
7
  * Used by component renderers to render their children.
@@ -14,7 +14,7 @@ export interface UiRendererProps {
14
14
  readonly library: UiComponentLibrary;
15
15
  readonly viewId?: string;
16
16
  readonly emptyFallback?: ReactNode;
17
- readonly onAction?: (actionId: string, payloadJson: string) => void;
17
+ readonly onAction?: (actionId: string, payloadJson: string, options?: DispatchActionOptions) => void;
18
18
  readonly client?: IkonClient | null;
19
19
  readonly video?: IkonVideoPlayback | null;
20
20
  }
package/surface.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { UIStreamCategories } from '../shared/protocol/src/index.ts';
2
2
  import { UiStreamStore } from '../sdk/sdk-ui/src/index.ts';
3
- import { UiComponentLibrary } from './renderer';
3
+ import { DispatchActionOptions, UiComponentLibrary } from './renderer';
4
4
  import { IkonClient } from '../sdk/sdk/src/index.ts';
5
5
  export declare const IKON_UI_STREAM_CATEGORY: "ikon-ui";
6
6
  export type IkonUiCategory = UIStreamCategories | typeof IKON_UI_STREAM_CATEGORY | (string & {});
@@ -13,7 +13,7 @@ export interface IkonUiSurfaceProps {
13
13
  stores: ReadonlyMap<string, IkonUiStoreEntry>;
14
14
  registry: UiComponentLibrary;
15
15
  category?: IkonUiCategory;
16
- onAction?: (actionId: string, payload?: string) => void;
16
+ onAction?: (actionId: string, payload?: string, options?: DispatchActionOptions) => void;
17
17
  client?: IkonClient | null;
18
18
  }
19
19
  export declare const IkonUiSurface: import('react').MemoExoticComponent<({ stores, registry, category, onAction, client }: IkonUiSurfaceProps) => import("react").JSX.Element | null>;
@@ -1,284 +1,295 @@
1
1
  /* Ikon app-shell styles: the connection overlays, the toast strip and the hero layout.
2
2
 
3
- Override any of this from your own src/app.css — unlayered rules always win over these,
4
- whatever their specificity or import order. */
5
- @layer ikon {
6
- .ikon-app {
7
- display: flex;
8
- align-items: center;
9
- justify-content: center;
10
- padding: 32px max(20px, env(safe-area-inset-left)) calc(32px + env(safe-area-inset-bottom));
11
- box-sizing: border-box;
12
- }
3
+ Override any of them from your own src/app.css, which loads after this sheet: at equal
4
+ specificity yours wins, with no `!important`. A few rules here are more specific than one class
5
+ — `.ikon-hero h1`, `.ikon-reconnecting-chip span`, the `:hover` and `:focus` states — so match
6
+ that shape to override those. */
7
+ .ikon-app {
8
+ display: flex;
9
+ align-items: center;
10
+ justify-content: center;
11
+ padding: 32px max(20px, env(safe-area-inset-left)) calc(32px + env(safe-area-inset-bottom));
12
+ box-sizing: border-box;
13
+ }
13
14
 
14
- .ikon-hero {
15
- position: relative;
16
- z-index: 1;
17
- display: flex;
18
- flex-direction: column;
19
- align-items: center;
20
- gap: 16px;
21
- max-width: 460px;
22
- text-align: center;
23
- }
15
+ .ikon-hero {
16
+ position: relative;
17
+ z-index: 1;
18
+ display: flex;
19
+ flex-direction: column;
20
+ align-items: center;
21
+ gap: 16px;
22
+ max-width: 460px;
23
+ text-align: center;
24
+ }
24
25
 
25
- .ikon-hero h1 {
26
- margin: 0;
27
- font-family: var(--ikon-font-display);
28
- font-size: clamp(24px, 7vw, 40px);
29
- font-weight: 600;
30
- line-height: 1.15;
31
- letter-spacing: -0.02em;
32
- color: var(--ikon-text-primary);
33
- text-wrap: balance;
34
- }
26
+ .ikon-hero h1 {
27
+ margin: 0;
28
+ font-family: var(--ikon-font-display);
29
+ font-size: clamp(24px, 7vw, 40px);
30
+ font-weight: 600;
31
+ line-height: 1.15;
32
+ letter-spacing: -0.02em;
33
+ color: var(--ikon-text-primary);
34
+ text-wrap: balance;
35
+ }
35
36
 
36
- .ikon-info {
37
- margin: 0;
38
- font-size: 15px;
39
- line-height: 1.6;
40
- color: var(--ikon-text-secondary);
41
- text-wrap: pretty;
42
- }
37
+ .ikon-info {
38
+ margin: 0;
39
+ font-size: 15px;
40
+ line-height: 1.6;
41
+ color: var(--ikon-text-secondary);
42
+ text-wrap: pretty;
43
+ }
43
44
 
44
- .ikon-error {
45
- margin: 0;
46
- font-family: var(--ikon-font-mono);
47
- font-size: 13px;
48
- line-height: 1.5;
49
- color: var(--ikon-status-error);
50
- word-break: break-word;
51
- }
45
+ .ikon-error {
46
+ margin: 0;
47
+ font-family: var(--ikon-font-mono);
48
+ font-size: 13px;
49
+ line-height: 1.5;
50
+ color: var(--ikon-status-error);
51
+ word-break: break-word;
52
+ }
52
53
 
53
- .ikon-connecting-overlay {
54
- position: fixed;
55
- top: 0;
56
- left: 0;
57
- right: 0;
58
- display: flex;
59
- justify-content: center;
60
- padding-top: max(16px, env(safe-area-inset-top));
61
- z-index: 9998;
62
- pointer-events: none;
63
- }
54
+ .ikon-connecting-overlay {
55
+ position: fixed;
56
+ top: 0;
57
+ left: 0;
58
+ right: 0;
59
+ display: flex;
60
+ justify-content: center;
61
+ padding-top: max(16px, env(safe-area-inset-top));
62
+ z-index: 9998;
63
+ pointer-events: none;
64
+ }
64
65
 
65
- .ikon-connecting-chip {
66
- display: flex;
67
- align-items: center;
68
- gap: 8px;
69
- padding: 8px 14px;
70
- background: var(--ikon-bg-card);
71
- border: 1px solid var(--ikon-border-secondary);
72
- border-radius: var(--ikon-radius-full);
73
- color: var(--ikon-text-secondary);
74
- font-family: var(--ikon-font-body);
75
- font-size: 13px;
76
- font-weight: 500;
77
- pointer-events: auto;
78
- animation: ikon-fade-in 0.3s ease-out;
79
- }
66
+ .ikon-connecting-chip {
67
+ display: flex;
68
+ align-items: center;
69
+ gap: 8px;
70
+ padding: 8px 14px;
71
+ background: var(--ikon-bg-card);
72
+ border: 1px solid var(--ikon-border-secondary);
73
+ border-radius: var(--ikon-radius-full);
74
+ color: var(--ikon-text-secondary);
75
+ font-family: var(--ikon-font-body);
76
+ font-size: 13px;
77
+ font-weight: 500;
78
+ pointer-events: auto;
79
+ animation: ikon-fade-in 0.3s ease-out;
80
+ }
80
81
 
81
- .ikon-connecting-spinner {
82
- width: 13px;
83
- height: 13px;
84
- border: 2px solid var(--ikon-border-primary);
85
- border-top-color: var(--ikon-text-tertiary);
86
- border-radius: var(--ikon-radius-full);
87
- animation: ikon-spin 0.9s linear infinite;
88
- }
82
+ .ikon-connecting-spinner {
83
+ width: 13px;
84
+ height: 13px;
85
+ border: 2px solid var(--ikon-border-primary);
86
+ border-top-color: var(--ikon-text-tertiary);
87
+ border-radius: var(--ikon-radius-full);
88
+ animation: ikon-spin 0.9s linear infinite;
89
+ }
89
90
 
90
- .ikon-reconnecting-overlay,
91
- .ikon-offline-overlay {
92
- position: fixed;
93
- inset: 0;
94
- display: flex;
95
- align-items: center;
96
- justify-content: center;
97
- padding: 24px;
98
- z-index: 9999;
99
- background: var(--ikon-overlay-scrim);
100
- backdrop-filter: blur(8px);
101
- -webkit-backdrop-filter: blur(8px);
102
- animation: ikon-fade-in 0.4s ease-out;
103
- }
91
+ .ikon-reconnecting-overlay,
92
+ .ikon-offline-overlay {
93
+ position: fixed;
94
+ /* The `inset` shorthand is Chromium 87; the longhands position this on older screens. */
95
+ top: 0;
96
+ right: 0;
97
+ bottom: 0;
98
+ left: 0;
99
+ inset: 0;
100
+ display: flex;
101
+ align-items: center;
102
+ justify-content: center;
103
+ padding: 24px;
104
+ z-index: 9999;
105
+ background: var(--ikon-overlay-scrim);
106
+ /* The prefixed form first: the minifier folds this pair into whichever is written last, and
107
+ Chromium has dropped `-webkit-backdrop-filter`, so standard-last is the one that blurs. */
108
+ -webkit-backdrop-filter: blur(8px);
109
+ backdrop-filter: blur(8px);
110
+ animation: ikon-fade-in 0.4s ease-out;
111
+ }
104
112
 
105
- .ikon-reconnecting-chip,
106
- .ikon-offline-chip {
107
- box-sizing: border-box;
108
- display: flex;
109
- flex-direction: column;
110
- align-items: center;
111
- gap: 8px;
112
- width: 100%;
113
- max-width: 380px;
114
- text-align: center;
115
- color: var(--ikon-text-primary);
116
- font-family: var(--ikon-font-body);
117
- }
113
+ .ikon-reconnecting-chip,
114
+ .ikon-offline-chip {
115
+ box-sizing: border-box;
116
+ display: flex;
117
+ flex-direction: column;
118
+ align-items: center;
119
+ gap: 8px;
120
+ width: 100%;
121
+ max-width: 380px;
122
+ text-align: center;
123
+ color: var(--ikon-text-primary);
124
+ font-family: var(--ikon-font-body);
125
+ }
118
126
 
119
- .ikon-reconnecting-spinner {
120
- width: 28px;
121
- height: 28px;
122
- margin-bottom: 4px;
123
- border: 2px solid var(--ikon-border-primary);
124
- border-top-color: var(--ikon-text-tertiary);
125
- border-radius: var(--ikon-radius-full);
126
- animation: ikon-spin 0.9s linear infinite;
127
- }
127
+ .ikon-reconnecting-spinner {
128
+ width: 28px;
129
+ height: 28px;
130
+ margin-bottom: 4px;
131
+ border: 2px solid var(--ikon-border-primary);
132
+ border-top-color: var(--ikon-text-tertiary);
133
+ border-radius: var(--ikon-radius-full);
134
+ animation: ikon-spin 0.9s linear infinite;
135
+ }
128
136
 
129
- .ikon-reconnecting-chip span {
130
- font-size: 15px;
131
- font-weight: 500;
132
- color: var(--ikon-text-secondary);
133
- }
137
+ .ikon-reconnecting-chip span {
138
+ font-size: 15px;
139
+ font-weight: 500;
140
+ color: var(--ikon-text-secondary);
141
+ }
134
142
 
135
- .ikon-offline-title {
136
- font-family: var(--ikon-font-display);
137
- font-size: clamp(20px, 5.5vw, 24px);
138
- font-weight: 600;
139
- line-height: 1.25;
140
- letter-spacing: -0.015em;
141
- text-wrap: balance;
142
- }
143
+ .ikon-offline-title {
144
+ font-family: var(--ikon-font-display);
145
+ font-size: clamp(20px, 5.5vw, 24px);
146
+ font-weight: 600;
147
+ line-height: 1.25;
148
+ letter-spacing: -0.015em;
149
+ text-wrap: balance;
150
+ }
143
151
 
144
- .ikon-offline-message {
145
- font-size: 14px;
146
- line-height: 1.6;
147
- color: var(--ikon-text-secondary);
148
- text-wrap: pretty;
149
- }
152
+ .ikon-offline-message {
153
+ font-size: 14px;
154
+ line-height: 1.6;
155
+ color: var(--ikon-text-secondary);
156
+ text-wrap: pretty;
157
+ }
150
158
 
151
- .ikon-offline-error {
152
- margin-top: 6px;
153
- font-family: var(--ikon-font-mono);
154
- font-size: 12px;
155
- line-height: 1.5;
156
- color: var(--ikon-text-quaternary);
157
- max-width: 100%;
158
- word-break: break-word;
159
- }
159
+ .ikon-offline-error {
160
+ margin-top: 6px;
161
+ font-family: var(--ikon-font-mono);
162
+ font-size: 12px;
163
+ line-height: 1.5;
164
+ color: var(--ikon-text-quaternary);
165
+ max-width: 100%;
166
+ word-break: break-word;
167
+ }
160
168
 
161
- /* An installed PWA has no reload control the user can reach, so this button is the only way back
162
- into the app — sized for a thumb rather than as a secondary affordance. */
163
- .ikon-offline-action {
164
- display: flex;
165
- align-items: center;
166
- justify-content: center;
167
- min-width: 160px;
168
- min-height: 44px;
169
- margin-top: 12px;
170
- padding: 0 20px;
171
- background: var(--ikon-bg-solid);
172
- border: 1px solid transparent;
173
- border-radius: var(--ikon-radius-md);
174
- font-family: inherit;
175
- font-size: 15px;
176
- font-weight: 500;
177
- line-height: 1;
178
- cursor: pointer;
179
- transition: background-color 0.15s ease;
180
- }
169
+ /* An installed PWA has no reload control the user can reach, so this button is the only way back
170
+ into the app — sized for a thumb rather than as a secondary affordance. */
171
+ .ikon-offline-action {
172
+ display: flex;
173
+ align-items: center;
174
+ justify-content: center;
175
+ min-width: 160px;
176
+ min-height: 44px;
177
+ margin-top: 12px;
178
+ padding: 0 20px;
179
+ background: var(--ikon-bg-solid);
180
+ border: 1px solid transparent;
181
+ border-radius: var(--ikon-radius-md);
182
+ font-family: inherit;
183
+ font-size: 15px;
184
+ font-weight: 500;
185
+ line-height: 1;
186
+ cursor: pointer;
187
+ transition: background-color 0.15s ease;
188
+ }
181
189
 
182
- /* Crosswind's preflight resets `button { color: inherit }` unlayered, and an unlayered rule beats
183
- a layered one whatever its specificity — so colouring the button itself loses the contrast and
184
- paints the label in the chip's text colour on the solid fill. The span is not something the
185
- reset targets, which keeps this a normal cascade an app can still override without !important. */
186
- .ikon-offline-action-label {
187
- color: var(--ikon-text-on-solid);
188
- }
190
+ /* Crosswind's preflight resets `button { color: inherit }` unlayered, and an unlayered rule beats
191
+ a layered one whatever its specificity — so colouring the button itself loses the contrast and
192
+ paints the label in the chip's text colour on the solid fill. The span is not something the
193
+ reset targets, which keeps this a normal cascade an app can still override without !important. */
194
+ .ikon-offline-action-label {
195
+ color: var(--ikon-text-on-solid);
196
+ }
189
197
 
190
- .ikon-offline-action:hover {
191
- background: var(--ikon-bg-solid-hover);
192
- }
198
+ .ikon-offline-action:hover {
199
+ background: var(--ikon-bg-solid-hover);
200
+ }
193
201
 
194
- .ikon-offline-action:focus-visible {
195
- outline: 2px solid var(--ikon-focus-ring);
196
- outline-offset: 2px;
197
- }
202
+ .ikon-offline-action:focus {
203
+ outline: 2px solid var(--ikon-focus-ring);
204
+ outline-offset: 2px;
205
+ }
198
206
 
199
- @keyframes ikon-fade-in {
200
- from { opacity: 0; }
201
- to { opacity: 1; }
202
- }
207
+ .ikon-offline-action:focus:not(:focus-visible) {
208
+ outline: none;
209
+ }
203
210
 
204
- @media (prefers-reduced-motion: reduce) {
205
- .ikon-connecting-spinner,
206
- .ikon-reconnecting-spinner {
207
- animation-duration: 2.4s;
208
- }
209
- }
211
+ @keyframes ikon-fade-in {
212
+ from { opacity: 0; }
213
+ to { opacity: 1; }
214
+ }
210
215
 
211
- .ikon-toast-overlay {
212
- position: fixed;
213
- top: 0;
214
- left: 0;
215
- right: 0;
216
- display: flex;
217
- flex-direction: column;
218
- align-items: center;
219
- gap: 8px;
220
- padding-top: max(16px, env(safe-area-inset-top));
221
- z-index: 9998;
222
- pointer-events: none;
216
+ @media (prefers-reduced-motion: reduce) {
217
+ .ikon-connecting-spinner,
218
+ .ikon-reconnecting-spinner {
219
+ animation-duration: 2.4s;
223
220
  }
221
+ }
224
222
 
225
- .ikon-toast-overlay-chip {
226
- display: flex;
227
- align-items: center;
228
- gap: 8px;
229
- max-width: min(440px, calc(100vw - 32px));
230
- padding: 8px 14px;
231
- border: 1px solid var(--ikon-border-secondary);
232
- border-radius: var(--ikon-radius-lg);
233
- background: var(--ikon-bg-card);
234
- color: var(--ikon-text-primary);
235
- font-family: var(--ikon-font-body);
236
- font-size: 13px;
237
- font-weight: 500;
238
- pointer-events: auto;
239
- cursor: pointer;
240
- animation: ikon-fade-in 0.3s ease-out;
241
- }
223
+ .ikon-toast-overlay {
224
+ position: fixed;
225
+ top: 0;
226
+ left: 0;
227
+ right: 0;
228
+ display: flex;
229
+ flex-direction: column;
230
+ align-items: center;
231
+ gap: 8px;
232
+ padding-top: max(16px, env(safe-area-inset-top));
233
+ z-index: 9998;
234
+ pointer-events: none;
235
+ }
242
236
 
243
- .ikon-toast-overlay-chip--warn {
244
- border-left: 3px solid var(--ikon-status-warning);
245
- }
237
+ .ikon-toast-overlay-chip {
238
+ display: flex;
239
+ align-items: center;
240
+ gap: 8px;
241
+ max-width: min(440px, calc(100vw - 32px));
242
+ padding: 8px 14px;
243
+ border: 1px solid var(--ikon-border-secondary);
244
+ border-radius: var(--ikon-radius-lg);
245
+ background: var(--ikon-bg-card);
246
+ color: var(--ikon-text-primary);
247
+ font-family: var(--ikon-font-body);
248
+ font-size: 13px;
249
+ font-weight: 500;
250
+ pointer-events: auto;
251
+ cursor: pointer;
252
+ animation: ikon-fade-in 0.3s ease-out;
253
+ }
246
254
 
247
- .ikon-toast-overlay-chip--warn .ikon-toast-overlay-icon {
248
- color: var(--ikon-status-warning);
249
- }
255
+ .ikon-toast-overlay-chip--warn {
256
+ border-left: 3px solid var(--ikon-status-warning);
257
+ }
250
258
 
251
- .ikon-toast-overlay-chip--error {
252
- border-left: 3px solid var(--ikon-status-error);
253
- }
259
+ .ikon-toast-overlay-chip--warn .ikon-toast-overlay-icon {
260
+ color: var(--ikon-status-warning);
261
+ }
254
262
 
255
- .ikon-toast-overlay-chip--error .ikon-toast-overlay-icon {
256
- color: var(--ikon-status-error);
257
- }
263
+ .ikon-toast-overlay-chip--error {
264
+ border-left: 3px solid var(--ikon-status-error);
265
+ }
258
266
 
259
- .ikon-toast-overlay-icon {
260
- flex-shrink: 0;
261
- font-size: 13px;
262
- line-height: 1;
263
- }
267
+ .ikon-toast-overlay-chip--error .ikon-toast-overlay-icon {
268
+ color: var(--ikon-status-error);
269
+ }
264
270
 
265
- .ikon-toast-overlay-content {
266
- display: flex;
267
- align-items: baseline;
268
- gap: 6px;
269
- min-width: 0;
270
- }
271
+ .ikon-toast-overlay-icon {
272
+ flex-shrink: 0;
273
+ font-size: 13px;
274
+ line-height: 1;
275
+ }
271
276
 
272
- .ikon-toast-overlay-component {
273
- flex: none;
274
- font-family: var(--ikon-font-mono);
275
- font-size: 11px;
276
- color: var(--ikon-text-quaternary);
277
- }
277
+ .ikon-toast-overlay-content {
278
+ display: flex;
279
+ align-items: baseline;
280
+ gap: 6px;
281
+ min-width: 0;
282
+ }
278
283
 
279
- .ikon-toast-overlay-message {
280
- font-size: 13px;
281
- white-space: pre-wrap;
282
- word-break: break-word;
283
- }
284
+ .ikon-toast-overlay-component {
285
+ flex: none;
286
+ font-family: var(--ikon-font-mono);
287
+ font-size: 11px;
288
+ color: var(--ikon-text-quaternary);
289
+ }
290
+
291
+ .ikon-toast-overlay-message {
292
+ font-size: 13px;
293
+ white-space: pre-wrap;
294
+ word-break: break-word;
284
295
  }