@genesislcap/ai-assistant 14.458.1-GENC-0.3 → 14.458.2
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/dist/ai-assistant.api.json +10 -37
- package/dist/ai-assistant.d.ts +4 -36
- package/dist/dts/main/main.d.ts.map +1 -1
- package/dist/dts/main/main.styles.d.ts.map +1 -1
- package/dist/dts/main/main.template.d.ts.map +1 -1
- package/dist/dts/main/main.types.d.ts +4 -34
- package/dist/dts/main/main.types.d.ts.map +1 -1
- package/dist/esm/main/main.js +9 -18
- package/dist/esm/main/main.styles.js +6 -38
- package/dist/esm/main/main.template.js +16 -33
- package/dist/esm/main/main.types.js +3 -34
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +16 -16
- package/src/main/main.styles.ts +6 -38
- package/src/main/main.template.ts +17 -36
- package/src/main/main.ts +8 -20
- package/src/main/main.types.ts +5 -42
- package/dist/dts/components/waves-indicator.d.ts +0 -30
- package/dist/dts/components/waves-indicator.d.ts.map +0 -1
- package/dist/dts/utils/animation-exclusivity.d.ts +0 -23
- package/dist/dts/utils/animation-exclusivity.d.ts.map +0 -1
- package/dist/dts/utils/animation-exclusivity.test.d.ts +0 -2
- package/dist/dts/utils/animation-exclusivity.test.d.ts.map +0 -1
- package/dist/esm/components/waves-indicator.js +0 -180
- package/dist/esm/utils/animation-exclusivity.js +0 -33
- package/dist/esm/utils/animation-exclusivity.test.js +0 -41
- package/src/components/waves-indicator.ts +0 -212
- package/src/utils/animation-exclusivity.test.ts +0 -53
- package/src/utils/animation-exclusivity.ts +0 -40
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@genesislcap/ai-assistant",
|
|
3
3
|
"description": "Genesis AI Assistant micro-frontend",
|
|
4
|
-
"version": "14.458.
|
|
4
|
+
"version": "14.458.2",
|
|
5
5
|
"license": "SEE LICENSE IN license.txt",
|
|
6
6
|
"main": "dist/esm/index.js",
|
|
7
7
|
"types": "dist/ai-assistant.d.ts",
|
|
@@ -64,24 +64,24 @@
|
|
|
64
64
|
}
|
|
65
65
|
},
|
|
66
66
|
"devDependencies": {
|
|
67
|
-
"@genesislcap/foundation-testing": "14.458.
|
|
68
|
-
"@genesislcap/genx": "14.458.
|
|
69
|
-
"@genesislcap/rollup-builder": "14.458.
|
|
70
|
-
"@genesislcap/ts-builder": "14.458.
|
|
71
|
-
"@genesislcap/uvu-playwright-builder": "14.458.
|
|
72
|
-
"@genesislcap/vite-builder": "14.458.
|
|
73
|
-
"@genesislcap/webpack-builder": "14.458.
|
|
67
|
+
"@genesislcap/foundation-testing": "14.458.2",
|
|
68
|
+
"@genesislcap/genx": "14.458.2",
|
|
69
|
+
"@genesislcap/rollup-builder": "14.458.2",
|
|
70
|
+
"@genesislcap/ts-builder": "14.458.2",
|
|
71
|
+
"@genesislcap/uvu-playwright-builder": "14.458.2",
|
|
72
|
+
"@genesislcap/vite-builder": "14.458.2",
|
|
73
|
+
"@genesislcap/webpack-builder": "14.458.2",
|
|
74
74
|
"@types/dompurify": "^3.0.5",
|
|
75
75
|
"@types/marked": "^5.0.2"
|
|
76
76
|
},
|
|
77
77
|
"dependencies": {
|
|
78
|
-
"@genesislcap/foundation-ai": "14.458.
|
|
79
|
-
"@genesislcap/foundation-logger": "14.458.
|
|
80
|
-
"@genesislcap/foundation-redux": "14.458.
|
|
81
|
-
"@genesislcap/foundation-ui": "14.458.
|
|
82
|
-
"@genesislcap/foundation-utils": "14.458.
|
|
83
|
-
"@genesislcap/rapid-design-system": "14.458.
|
|
84
|
-
"@genesislcap/web-core": "14.458.
|
|
78
|
+
"@genesislcap/foundation-ai": "14.458.2",
|
|
79
|
+
"@genesislcap/foundation-logger": "14.458.2",
|
|
80
|
+
"@genesislcap/foundation-redux": "14.458.2",
|
|
81
|
+
"@genesislcap/foundation-ui": "14.458.2",
|
|
82
|
+
"@genesislcap/foundation-utils": "14.458.2",
|
|
83
|
+
"@genesislcap/rapid-design-system": "14.458.2",
|
|
84
|
+
"@genesislcap/web-core": "14.458.2",
|
|
85
85
|
"dompurify": "^3.3.1",
|
|
86
86
|
"marked": "^17.0.3"
|
|
87
87
|
},
|
|
@@ -93,5 +93,5 @@
|
|
|
93
93
|
"publishConfig": {
|
|
94
94
|
"access": "public"
|
|
95
95
|
},
|
|
96
|
-
"gitHead": "
|
|
96
|
+
"gitHead": "d2445453c001d9ab1377d1c0a6d90e2b65adb448"
|
|
97
97
|
}
|
package/src/main/main.styles.ts
CHANGED
|
@@ -101,22 +101,14 @@ export const styles = css`
|
|
|
101
101
|
animation: settings-slide-out 0.2s ease-in forwards;
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
width: 100px;
|
|
104
|
+
rapid-multiselect::part(root) {
|
|
105
|
+
min-width: 80px;
|
|
106
|
+
width: 300%;
|
|
108
107
|
}
|
|
109
108
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
(see the layout rules below), so the dropdown must anchor to whichever side
|
|
114
|
-
keeps it inside the panel. Default (narrow) layout puts the control on the
|
|
115
|
-
LEFT, so the dropdown grows rightward. */
|
|
116
|
-
rapid-categorized-multiselect::part(options) {
|
|
117
|
-
width: 200px;
|
|
118
|
-
left: 0;
|
|
119
|
-
right: auto;
|
|
109
|
+
rapid-multiselect::part(control),
|
|
110
|
+
.settings-panel > [part='download-button'] {
|
|
111
|
+
width: fit-content;
|
|
120
112
|
}
|
|
121
113
|
|
|
122
114
|
.settings-panel > [part='toggle-tool-calls'] {
|
|
@@ -135,7 +127,6 @@ export const styles = css`
|
|
|
135
127
|
}
|
|
136
128
|
|
|
137
129
|
.settings-panel > [part='download-button'] {
|
|
138
|
-
width: fit-content;
|
|
139
130
|
grid-column: 2;
|
|
140
131
|
grid-row: 2;
|
|
141
132
|
}
|
|
@@ -185,13 +176,6 @@ export const styles = css`
|
|
|
185
176
|
.settings-panel > .settings-animations {
|
|
186
177
|
grid-row: 2;
|
|
187
178
|
}
|
|
188
|
-
|
|
189
|
-
/* Control now sits on the RIGHT (justify-self: end / margin-left: auto in
|
|
190
|
-
the wider layouts), so the dropdown grows leftward to stay in the panel. */
|
|
191
|
-
rapid-categorized-multiselect::part(options) {
|
|
192
|
-
left: auto;
|
|
193
|
-
right: 0;
|
|
194
|
-
}
|
|
195
179
|
}
|
|
196
180
|
|
|
197
181
|
@container (min-width: 750px) {
|
|
@@ -825,22 +809,6 @@ export const styles = css`
|
|
|
825
809
|
}
|
|
826
810
|
}
|
|
827
811
|
|
|
828
|
-
.thinking-waves {
|
|
829
|
-
display: flex;
|
|
830
|
-
flex-direction: column;
|
|
831
|
-
align-items: center;
|
|
832
|
-
align-self: center;
|
|
833
|
-
gap: 6px;
|
|
834
|
-
padding: calc(var(--design-unit) * 2px) calc(var(--design-unit) * 3px);
|
|
835
|
-
}
|
|
836
|
-
|
|
837
|
-
.thinking-caption {
|
|
838
|
-
font-size: var(--type-ramp-minus-1-font-size, 12px);
|
|
839
|
-
line-height: var(--type-ramp-minus-1-line-height, 16px);
|
|
840
|
-
color: var(--neutral-foreground-rest);
|
|
841
|
-
opacity: 70%;
|
|
842
|
-
}
|
|
843
|
-
|
|
844
812
|
.attachment-chips {
|
|
845
813
|
display: flex;
|
|
846
814
|
flex-wrap: wrap;
|
|
@@ -40,6 +40,10 @@ function unknownToolPayload(tc: ChatToolCall): string {
|
|
|
40
40
|
return lines.join('\n');
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
const animationItemRenderer = (option: any): ViewTemplate => html`
|
|
44
|
+
<span part="option-label" title="${() => option.tooltip}">${() => option.label}</span>
|
|
45
|
+
`;
|
|
46
|
+
|
|
43
47
|
const HALO_SPEED_DEFAULT = 1.5;
|
|
44
48
|
const HALO_SPEED_ORCHESTRATING = 0.4;
|
|
45
49
|
const HALO_BORDER_SIZE_DEFAULT = 3;
|
|
@@ -48,10 +52,9 @@ const HALO_BORDER_SIZE_DEFAULT = 3;
|
|
|
48
52
|
const SESSION_COST_DECIMALS = 4;
|
|
49
53
|
|
|
50
54
|
const animationOptions = Object.entries(ANIMATION_DEFS).map(([value, def]) => ({
|
|
51
|
-
type: def.category,
|
|
52
55
|
value,
|
|
53
56
|
label: def.label,
|
|
54
|
-
|
|
57
|
+
tooltip: def.tooltip,
|
|
55
58
|
}));
|
|
56
59
|
|
|
57
60
|
// Avatar markup is owned by the component (`assistantIconSafe` / `userIconSafe`),
|
|
@@ -173,30 +176,6 @@ const liveSubAgentTraceTemplate = html<FoundationAiAssistant>`
|
|
|
173
176
|
</div>
|
|
174
177
|
`;
|
|
175
178
|
|
|
176
|
-
// The two interchangeable loading indicators. These MUST be stable module-level
|
|
177
|
-
// instances: the binding that selects between them reads `enabledAnimations`,
|
|
178
|
-
// which is backed by the redux store proxy and re-evaluates on every change to
|
|
179
|
-
// the aiAssistant slice (i.e. every new message, including hidden tool-call and
|
|
180
|
-
// thinking-step messages). Returning a fresh `html` instance from that binding
|
|
181
|
-
// would make FAST tear down and rebuild the indicator DOM each time, restarting
|
|
182
|
-
// the dots' CSS animation and the waves' rAF loop. Stable references let FAST
|
|
183
|
-
// reuse the existing view so the animation runs uninterrupted.
|
|
184
|
-
const thinkingDotsTemplate = html<FoundationAiAssistant>`
|
|
185
|
-
<div class="thinking-dots">
|
|
186
|
-
<div class="dot dot-1"></div>
|
|
187
|
-
<div class="dot dot-2"></div>
|
|
188
|
-
<div class="dot dot-3"></div>
|
|
189
|
-
<div class="dot dot-4"></div>
|
|
190
|
-
</div>
|
|
191
|
-
`;
|
|
192
|
-
|
|
193
|
-
const thinkingWavesTemplate = html<FoundationAiAssistant>`
|
|
194
|
-
<div class="thinking-waves" part="thinking-waves">
|
|
195
|
-
<ai-waves-indicator></ai-waves-indicator>
|
|
196
|
-
<span class="thinking-caption">Thinking...</span>
|
|
197
|
-
</div>
|
|
198
|
-
`;
|
|
199
|
-
|
|
200
179
|
// ─── Public factory ───────────────────────────────────────────────────────────
|
|
201
180
|
|
|
202
181
|
/** @internal */
|
|
@@ -205,7 +184,7 @@ export const FoundationAiAssistantTemplate = (
|
|
|
205
184
|
): ViewTemplate<FoundationAiAssistant> => {
|
|
206
185
|
const buttonTag = `${designSystemPrefix}-button`;
|
|
207
186
|
const switchTag = `${designSystemPrefix}-switch`;
|
|
208
|
-
const
|
|
187
|
+
const multiselectTag = `${designSystemPrefix}-multiselect`;
|
|
209
188
|
const textareaTag = `${designSystemPrefix}-text-area`;
|
|
210
189
|
const iconTag = `${designSystemPrefix}-icon`;
|
|
211
190
|
const progressTag = `${designSystemPrefix}-progress`;
|
|
@@ -494,14 +473,16 @@ ${(tc) => (tc.foldPath?.length ? `${tc.foldPath.join(' › ')} › ` : '')}<stro
|
|
|
494
473
|
html<FoundationAiAssistant>`
|
|
495
474
|
<div class="settings-animations">
|
|
496
475
|
<span class="settings-label">Animations</span>
|
|
497
|
-
<${
|
|
476
|
+
<${multiselectTag}
|
|
498
477
|
part="toggle-animations"
|
|
499
478
|
:selectedOptions=${(x) => x.enabledAnimations}
|
|
500
479
|
:options=${() => animationOptions}
|
|
480
|
+
:itemRenderer=${() => animationItemRenderer}
|
|
501
481
|
@selectionChange=${(x, c) =>
|
|
502
482
|
x.setEnabledAnimations((c.event as CustomEvent).detail)}
|
|
503
483
|
search="false"
|
|
504
|
-
|
|
484
|
+
all="false"
|
|
485
|
+
></${multiselectTag}>
|
|
505
486
|
</div>
|
|
506
487
|
`,
|
|
507
488
|
)}
|
|
@@ -609,9 +590,7 @@ ${(tc) => (tc.foldPath?.length ? `${tc.foldPath.join(' › ')} › ` : '')}<stro
|
|
|
609
590
|
${when(
|
|
610
591
|
(x) =>
|
|
611
592
|
x.showLoadingIndicator &&
|
|
612
|
-
(x.chatConfig.ui?.animations == null ||
|
|
613
|
-
x.enabledAnimations.includes('loading') ||
|
|
614
|
-
x.enabledAnimations.includes('waves')),
|
|
593
|
+
(x.chatConfig.ui?.animations == null || x.enabledAnimations.includes('loading')),
|
|
615
594
|
html<FoundationAiAssistant>`
|
|
616
595
|
<div class="message-row ai" part="thinking">
|
|
617
596
|
<div class="avatar">
|
|
@@ -624,10 +603,12 @@ ${(tc) => (tc.foldPath?.length ? `${tc.foldPath.join(' › ')} › ` : '')}<stro
|
|
|
624
603
|
<span class="avatar-icon" :innerHTML="${() => x.assistantIconSafe}"></span>
|
|
625
604
|
`}
|
|
626
605
|
</div>
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
606
|
+
<div class="thinking-dots">
|
|
607
|
+
<div class="dot dot-1"></div>
|
|
608
|
+
<div class="dot dot-2"></div>
|
|
609
|
+
<div class="dot dot-3"></div>
|
|
610
|
+
<div class="dot dot-4"></div>
|
|
611
|
+
</div>
|
|
631
612
|
</div>
|
|
632
613
|
`,
|
|
633
614
|
)}
|
package/src/main/main.ts
CHANGED
|
@@ -49,7 +49,6 @@ import { AiChatInteractionWrapper } from '../components/chat-interaction-wrapper
|
|
|
49
49
|
import { AiChatMarkdown } from '../components/chat-markdown/chat-markdown';
|
|
50
50
|
import { AiHaloOverlay } from '../components/halo-overlay';
|
|
51
51
|
import { OrchestratingDriver } from '../components/orchestrating-driver/orchestrating-driver';
|
|
52
|
-
import { AiWavesIndicator } from '../components/waves-indicator';
|
|
53
52
|
import type { AgentConfig } from '../config/config';
|
|
54
53
|
import {
|
|
55
54
|
recordMetaEvent,
|
|
@@ -67,7 +66,6 @@ import {
|
|
|
67
66
|
} from '../styles/ai-colours';
|
|
68
67
|
import { ChatSuggestions } from '../suggestions/chat-suggestions';
|
|
69
68
|
import { AnimatedPanelToggle } from '../utils/animated-panel-toggle';
|
|
70
|
-
import { resolveExclusiveLoadingStyle } from '../utils/animation-exclusivity';
|
|
71
69
|
import { logger } from '../utils/logger';
|
|
72
70
|
import { filterVisibleMessages, trailingInteractionRow } from '../utils/message-partition';
|
|
73
71
|
import { sumCosts } from '../utils/sum-costs';
|
|
@@ -82,7 +80,7 @@ import type {
|
|
|
82
80
|
SubmitMessageResult,
|
|
83
81
|
SuggestionsState,
|
|
84
82
|
} from './main.types';
|
|
85
|
-
import {
|
|
83
|
+
import { ALL_ANIMATIONS } from './main.types';
|
|
86
84
|
|
|
87
85
|
/** Context window sizes (in tokens) for known models. */
|
|
88
86
|
/**
|
|
@@ -139,7 +137,6 @@ avoidTreeShaking(
|
|
|
139
137
|
AiChatMarkdown,
|
|
140
138
|
AiChatInteractionWrapper,
|
|
141
139
|
AiHaloOverlay,
|
|
142
|
-
AiWavesIndicator,
|
|
143
140
|
AiChatBubble,
|
|
144
141
|
AiActivityHalo,
|
|
145
142
|
ChatSuggestions,
|
|
@@ -659,9 +656,7 @@ export class FoundationAiAssistant extends GenesisElement {
|
|
|
659
656
|
return;
|
|
660
657
|
}
|
|
661
658
|
const last = this.messages[this.messages.length - 1];
|
|
662
|
-
|
|
663
|
-
// interaction means the assistant is computing again (keep the halo).
|
|
664
|
-
if (last?.interaction && !last.interaction.resolved) {
|
|
659
|
+
if (last?.interaction) {
|
|
665
660
|
this.showHalo = 'no';
|
|
666
661
|
} else if (this.showHalo !== 'orchestrating') {
|
|
667
662
|
this.showHalo = 'agent';
|
|
@@ -1052,10 +1047,9 @@ export class FoundationAiAssistant extends GenesisElement {
|
|
|
1052
1047
|
this.showToolCalls = ui.showToolCalls === true;
|
|
1053
1048
|
this.showThinkingSteps = ui.showThinkingSteps === true;
|
|
1054
1049
|
this.showAgentSwitchIndicator = ui.showAgentSwitchIndicator === true;
|
|
1055
|
-
this.enabledAnimations =
|
|
1050
|
+
this.enabledAnimations =
|
|
1056
1051
|
(ui.animations?.enabled as AiAssistantAnimation[]) ??
|
|
1057
|
-
|
|
1058
|
-
);
|
|
1052
|
+
(ui.animations ? [...ALL_ANIMATIONS] : []);
|
|
1059
1053
|
|
|
1060
1054
|
const defaultAgent = this.chatConfig.picker?.defaultAgent;
|
|
1061
1055
|
if (defaultAgent && (this.agents ?? []).some((a) => a.name === defaultAgent)) {
|
|
@@ -1222,13 +1216,9 @@ export class FoundationAiAssistant extends GenesisElement {
|
|
|
1222
1216
|
// waiting for the user, not computing.
|
|
1223
1217
|
if (this.busy) {
|
|
1224
1218
|
const last = this.messages[this.messages.length - 1];
|
|
1225
|
-
|
|
1226
|
-
// the user. Once it's resolved — or for any normal step — the assistant is
|
|
1227
|
-
// computing again, so the indicator should resume (e.g. while it works out
|
|
1228
|
-
// the next planning question after the user answers a widget).
|
|
1229
|
-
if (last?.interaction && !last.interaction.resolved) {
|
|
1219
|
+
if (last?.interaction) {
|
|
1230
1220
|
this.stopLoadingTimer();
|
|
1231
|
-
} else {
|
|
1221
|
+
} else if (last?.role === 'assistant') {
|
|
1232
1222
|
this.startLoadingTimer();
|
|
1233
1223
|
}
|
|
1234
1224
|
}
|
|
@@ -1312,7 +1302,7 @@ export class FoundationAiAssistant extends GenesisElement {
|
|
|
1312
1302
|
});
|
|
1313
1303
|
}
|
|
1314
1304
|
|
|
1315
|
-
private static readonly DEFAULT_LOADING_DELAY_S =
|
|
1305
|
+
private static readonly DEFAULT_LOADING_DELAY_S = 5;
|
|
1316
1306
|
private static readonly DEFAULT_SUGGESTION_COUNT = 3;
|
|
1317
1307
|
private static readonly MS_PER_SECOND = 1000;
|
|
1318
1308
|
|
|
@@ -1516,9 +1506,7 @@ export class FoundationAiAssistant extends GenesisElement {
|
|
|
1516
1506
|
}
|
|
1517
1507
|
|
|
1518
1508
|
setEnabledAnimations(animations: AiAssistantAnimation[]) {
|
|
1519
|
-
|
|
1520
|
-
// disables the other (see resolveExclusiveLoadingStyle).
|
|
1521
|
-
this.enabledAnimations = resolveExclusiveLoadingStyle(animations, this.enabledAnimations);
|
|
1509
|
+
this.enabledAnimations = animations;
|
|
1522
1510
|
}
|
|
1523
1511
|
|
|
1524
1512
|
getDebugLog() {
|
package/src/main/main.types.ts
CHANGED
|
@@ -53,41 +53,24 @@ export type SuggestionsState =
|
|
|
53
53
|
export interface AiAssistantAnimationDef {
|
|
54
54
|
/** Display label shown in the settings multiselect. */
|
|
55
55
|
label: string;
|
|
56
|
-
/** Short description shown
|
|
57
|
-
|
|
58
|
-
/** Group heading the option is listed under in the settings multiselect. */
|
|
59
|
-
category: string;
|
|
56
|
+
/** Short description shown as a tooltip on the option. */
|
|
57
|
+
tooltip: string;
|
|
60
58
|
}
|
|
61
59
|
|
|
62
60
|
/**
|
|
63
61
|
* Registry of all available animations with their display metadata.
|
|
64
62
|
* Adding an entry here automatically extends the {@link AiAssistantAnimation} type.
|
|
65
63
|
*
|
|
66
|
-
* @remarks
|
|
67
|
-
* `loading` (dots) and `waves` are two interchangeable styles of the same
|
|
68
|
-
* "is the assistant working" indicator and are therefore grouped under the same
|
|
69
|
-
* {@link AiAssistantAnimationDef.category}. They are mutually exclusive — see
|
|
70
|
-
* `LOADING_STYLE_ANIMATIONS`.
|
|
71
|
-
*
|
|
72
64
|
* @beta
|
|
73
65
|
*/
|
|
74
66
|
export const ANIMATION_DEFS = {
|
|
75
67
|
loading: {
|
|
76
|
-
label: '
|
|
77
|
-
|
|
78
|
-
category: 'Loading style',
|
|
79
|
-
},
|
|
80
|
-
waves: {
|
|
81
|
-
label: 'Waves',
|
|
82
|
-
description:
|
|
83
|
-
'Shows glowing sine waves inside a circle while the assistant is generating a response.',
|
|
84
|
-
category: 'Loading style',
|
|
68
|
+
label: 'Loading indicator',
|
|
69
|
+
tooltip: 'Shows a pulsing animation while the assistant is generating a response.',
|
|
85
70
|
},
|
|
86
71
|
halo: {
|
|
87
72
|
label: 'Halo',
|
|
88
|
-
|
|
89
|
-
'Displays a glowing halo around the assistant avatar while a response is streaming.',
|
|
90
|
-
category: 'Effects',
|
|
73
|
+
tooltip: 'Displays a glowing halo around the assistant avatar while a response is streaming.',
|
|
91
74
|
},
|
|
92
75
|
} satisfies Record<string, AiAssistantAnimationDef>;
|
|
93
76
|
|
|
@@ -104,23 +87,3 @@ export type AiAssistantAnimation = keyof typeof ANIMATION_DEFS;
|
|
|
104
87
|
* @internal
|
|
105
88
|
*/
|
|
106
89
|
export const ALL_ANIMATIONS = Object.keys(ANIMATION_DEFS) as AiAssistantAnimation[];
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* The interchangeable "assistant is working" loading-indicator styles. At most
|
|
110
|
-
* one of these may be enabled at a time — enabling one disables the other.
|
|
111
|
-
*
|
|
112
|
-
* @internal
|
|
113
|
-
*/
|
|
114
|
-
export const LOADING_STYLE_ANIMATIONS = [
|
|
115
|
-
'loading',
|
|
116
|
-
'waves',
|
|
117
|
-
] as const satisfies readonly AiAssistantAnimation[];
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Animations enabled by default when a consumer opts into the animations
|
|
121
|
-
* feature without specifying an explicit `enabled` list. Keeps the dots loading
|
|
122
|
-
* style (the long-standing default); the waves style is opt-in.
|
|
123
|
-
*
|
|
124
|
-
* @internal
|
|
125
|
-
*/
|
|
126
|
-
export const DEFAULT_ANIMATIONS: AiAssistantAnimation[] = ['loading', 'halo'];
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { GenesisElement } from '@genesislcap/web-core';
|
|
2
|
-
/**
|
|
3
|
-
* Animated "waves inside a circle" loading indicator — coloured sine waves that
|
|
4
|
-
* slosh like glowing liquid inside a circular window, ringed by a rotating
|
|
5
|
-
* gradient halo (the same effect as `<ai-halo-overlay>`).
|
|
6
|
-
*
|
|
7
|
-
* Visual sibling of the dots loading indicator; the two are interchangeable
|
|
8
|
-
* styles of the same "assistant is working" state.
|
|
9
|
-
*
|
|
10
|
-
* @example
|
|
11
|
-
* ```html
|
|
12
|
-
* <ai-waves-indicator size="56"></ai-waves-indicator>
|
|
13
|
-
* ```
|
|
14
|
-
*
|
|
15
|
-
* @beta
|
|
16
|
-
*/
|
|
17
|
-
export declare class AiWavesIndicator extends GenesisElement {
|
|
18
|
-
/** Diameter of the circular window in px. Default: 56. */
|
|
19
|
-
size: number;
|
|
20
|
-
sizeChanged(): void;
|
|
21
|
-
private frame;
|
|
22
|
-
private animFrame?;
|
|
23
|
-
private wavePaths?;
|
|
24
|
-
connectedCallback(): void;
|
|
25
|
-
disconnectedCallback(): void;
|
|
26
|
-
private tick;
|
|
27
|
-
/** Trace one wave's polyline `d` attribute for the given frame. */
|
|
28
|
-
private static buildWavePath;
|
|
29
|
-
}
|
|
30
|
-
//# sourceMappingURL=waves-indicator.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"waves-indicator.d.ts","sourceRoot":"","sources":["../../../src/components/waves-indicator.ts"],"names":[],"mappings":"AACA,OAAO,EAA4B,cAAc,EAAQ,MAAM,uBAAuB,CAAC;AAwFvF;;;;;;;;;;;;;;GAcG;AACH,qBAkDa,gBAAiB,SAAQ,cAAc;IAClD,0DAA0D;IACC,IAAI,EAAE,MAAM,CAAsB;IAE7F,WAAW;IAQX,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,SAAS,CAAC,CAAS;IAC3B,OAAO,CAAC,SAAS,CAAC,CAAmB;IAErC,iBAAiB;IAKjB,oBAAoB;IAQpB,OAAO,CAAC,IAAI;IAYZ,mEAAmE;IACnE,OAAO,CAAC,MAAM,CAAC,aAAa;CAY7B"}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import type { AiAssistantAnimation } from '../main/main.types';
|
|
2
|
-
/**
|
|
3
|
-
* Enforces that at most one loading-indicator style (dots vs. waves) is enabled
|
|
4
|
-
* at a time. The two are alternative presentations of the same "assistant is
|
|
5
|
-
* working" state, so selecting one must deselect the other.
|
|
6
|
-
*
|
|
7
|
-
* The settings control is a multiselect (checkboxes), which permits selecting
|
|
8
|
-
* both; this resolver makes the loading-style group behave like a radio group
|
|
9
|
-
* by dropping the previously-selected style whenever a new one is added.
|
|
10
|
-
*
|
|
11
|
-
* @param next - The freshly-selected animation list (e.g. emitted by the
|
|
12
|
-
* multiselect, or read from consumer config).
|
|
13
|
-
* @param previous - The animation list in effect before this change. Used to
|
|
14
|
-
* work out which loading style was just added so the other can be dropped.
|
|
15
|
-
* Pass `[]` when resolving an initial/config value with no prior state.
|
|
16
|
-
* @returns `next` with at most one loading style retained. When both are
|
|
17
|
-
* present and neither is newly added (e.g. a misconfigured `enabled` list),
|
|
18
|
-
* the first entry of `LOADING_STYLE_ANIMATIONS` (dots) wins.
|
|
19
|
-
*
|
|
20
|
-
* @internal
|
|
21
|
-
*/
|
|
22
|
-
export declare function resolveExclusiveLoadingStyle(next: AiAssistantAnimation[], previous?: AiAssistantAnimation[]): AiAssistantAnimation[];
|
|
23
|
-
//# sourceMappingURL=animation-exclusivity.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"animation-exclusivity.d.ts","sourceRoot":"","sources":["../../../src/utils/animation-exclusivity.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAG/D;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,oBAAoB,EAAE,EAC5B,QAAQ,GAAE,oBAAoB,EAAO,GACpC,oBAAoB,EAAE,CAaxB"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"animation-exclusivity.test.d.ts","sourceRoot":"","sources":["../../../src/utils/animation-exclusivity.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
var AiWavesIndicator_1;
|
|
2
|
-
import { __decorate } from "tslib";
|
|
3
|
-
import { avoidTreeShaking } from '@genesislcap/foundation-utils';
|
|
4
|
-
import { attr, css, customElement, GenesisElement, html } from '@genesislcap/web-core';
|
|
5
|
-
import { AI_COLOUR_AMBER, AI_COLOUR_CYAN, AI_COLOUR_PINK, AI_COLOUR_VIOLET, } from '../styles/ai-colours';
|
|
6
|
-
import { AiHaloOverlay } from './halo-overlay';
|
|
7
|
-
const WAVES_DEFAULT_SIZE = 56;
|
|
8
|
-
/** CSS-ready form of `WAVES_DEFAULT_SIZE` (the `css` tag rejects raw numbers). */
|
|
9
|
-
const WAVES_DEFAULT_SIZE_CSS = `${WAVES_DEFAULT_SIZE}px`;
|
|
10
|
-
/** SVG coordinate space the waves are drawn in (square; the circle fills it). */
|
|
11
|
-
const VIEWBOX = 120;
|
|
12
|
-
const CENTRE = VIEWBOX / 2;
|
|
13
|
-
/** Horizontal sampling step when tracing each wave path. Lower = smoother. */
|
|
14
|
-
const SAMPLE_STEP = 6;
|
|
15
|
-
const WAVES = [
|
|
16
|
-
{
|
|
17
|
-
colour: AI_COLOUR_AMBER,
|
|
18
|
-
amplitude: 11,
|
|
19
|
-
frequency: 0.085,
|
|
20
|
-
phaseSpeed: 0.05,
|
|
21
|
-
verticalOffset: -6,
|
|
22
|
-
slosh: 6,
|
|
23
|
-
sloshFrequency: 0.018,
|
|
24
|
-
sloshSpeed: 0.021,
|
|
25
|
-
},
|
|
26
|
-
{
|
|
27
|
-
colour: AI_COLOUR_PINK,
|
|
28
|
-
amplitude: 14,
|
|
29
|
-
frequency: 0.07,
|
|
30
|
-
phaseSpeed: -0.043,
|
|
31
|
-
verticalOffset: -2,
|
|
32
|
-
slosh: 7,
|
|
33
|
-
sloshFrequency: 0.022,
|
|
34
|
-
sloshSpeed: -0.017,
|
|
35
|
-
},
|
|
36
|
-
{
|
|
37
|
-
colour: AI_COLOUR_CYAN,
|
|
38
|
-
amplitude: 13,
|
|
39
|
-
frequency: 0.095,
|
|
40
|
-
phaseSpeed: 0.037,
|
|
41
|
-
verticalOffset: 2,
|
|
42
|
-
slosh: 5,
|
|
43
|
-
sloshFrequency: 0.015,
|
|
44
|
-
sloshSpeed: 0.025,
|
|
45
|
-
},
|
|
46
|
-
{
|
|
47
|
-
colour: AI_COLOUR_VIOLET,
|
|
48
|
-
amplitude: 10,
|
|
49
|
-
frequency: 0.06,
|
|
50
|
-
phaseSpeed: -0.055,
|
|
51
|
-
verticalOffset: 6,
|
|
52
|
-
slosh: 8,
|
|
53
|
-
sloshFrequency: 0.025,
|
|
54
|
-
sloshSpeed: -0.013,
|
|
55
|
-
},
|
|
56
|
-
];
|
|
57
|
-
const wavePathsMarkup = WAVES.map((w, i) => `<path class="wave" data-wave="${i}" stroke="${w.colour}" />`).join('');
|
|
58
|
-
/**
|
|
59
|
-
* Animated "waves inside a circle" loading indicator — coloured sine waves that
|
|
60
|
-
* slosh like glowing liquid inside a circular window, ringed by a rotating
|
|
61
|
-
* gradient halo (the same effect as `<ai-halo-overlay>`).
|
|
62
|
-
*
|
|
63
|
-
* Visual sibling of the dots loading indicator; the two are interchangeable
|
|
64
|
-
* styles of the same "assistant is working" state.
|
|
65
|
-
*
|
|
66
|
-
* @example
|
|
67
|
-
* ```html
|
|
68
|
-
* <ai-waves-indicator size="56"></ai-waves-indicator>
|
|
69
|
-
* ```
|
|
70
|
-
*
|
|
71
|
-
* @beta
|
|
72
|
-
*/
|
|
73
|
-
let AiWavesIndicator = AiWavesIndicator_1 = class AiWavesIndicator extends GenesisElement {
|
|
74
|
-
constructor() {
|
|
75
|
-
super(...arguments);
|
|
76
|
-
/** Diameter of the circular window in px. Default: 56. */
|
|
77
|
-
this.size = WAVES_DEFAULT_SIZE;
|
|
78
|
-
// A rAF loop drives the wave paths for the same reason `<ai-halo-overlay>`
|
|
79
|
-
// hand-drives its rotation: a pure-CSS approach can't produce per-frame sine
|
|
80
|
-
// geometry, and SMIL/`<animate>` can't express the combined travel + slosh.
|
|
81
|
-
this.frame = 0;
|
|
82
|
-
}
|
|
83
|
-
sizeChanged() {
|
|
84
|
-
this.style.setProperty('--waves-size', `${this.size}px`);
|
|
85
|
-
}
|
|
86
|
-
connectedCallback() {
|
|
87
|
-
super.connectedCallback();
|
|
88
|
-
this.tick();
|
|
89
|
-
}
|
|
90
|
-
disconnectedCallback() {
|
|
91
|
-
super.disconnectedCallback();
|
|
92
|
-
if (this.animFrame !== undefined) {
|
|
93
|
-
cancelAnimationFrame(this.animFrame);
|
|
94
|
-
this.animFrame = undefined;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
tick() {
|
|
98
|
-
var _a, _b;
|
|
99
|
-
if (!this.wavePaths) {
|
|
100
|
-
const paths = (_a = this.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelectorAll('.wave');
|
|
101
|
-
if (paths === null || paths === void 0 ? void 0 : paths.length)
|
|
102
|
-
this.wavePaths = Array.from(paths);
|
|
103
|
-
}
|
|
104
|
-
(_b = this.wavePaths) === null || _b === void 0 ? void 0 : _b.forEach((path, i) => {
|
|
105
|
-
path.setAttribute('d', AiWavesIndicator_1.buildWavePath(WAVES[i], this.frame));
|
|
106
|
-
});
|
|
107
|
-
this.frame += 1;
|
|
108
|
-
this.animFrame = requestAnimationFrame(() => this.tick());
|
|
109
|
-
}
|
|
110
|
-
/** Trace one wave's polyline `d` attribute for the given frame. */
|
|
111
|
-
static buildWavePath(cfg, frame) {
|
|
112
|
-
const segments = [];
|
|
113
|
-
for (let x = 0; x <= VIEWBOX; x += SAMPLE_STEP) {
|
|
114
|
-
const y = CENTRE +
|
|
115
|
-
cfg.verticalOffset +
|
|
116
|
-
cfg.amplitude * Math.sin(x * cfg.frequency + frame * cfg.phaseSpeed) +
|
|
117
|
-
cfg.slosh * Math.sin(x * cfg.sloshFrequency + frame * cfg.sloshSpeed);
|
|
118
|
-
segments.push(`${x},${y.toFixed(2)}`);
|
|
119
|
-
}
|
|
120
|
-
return `M ${segments.join(' L ')}`;
|
|
121
|
-
}
|
|
122
|
-
};
|
|
123
|
-
__decorate([
|
|
124
|
-
attr({ converter: { fromView: Number, toView: String } })
|
|
125
|
-
], AiWavesIndicator.prototype, "size", void 0);
|
|
126
|
-
AiWavesIndicator = AiWavesIndicator_1 = __decorate([
|
|
127
|
-
customElement({
|
|
128
|
-
name: 'ai-waves-indicator',
|
|
129
|
-
template: html `
|
|
130
|
-
<div class="window" role="img" aria-label="Assistant is working">
|
|
131
|
-
<svg class="waves" viewBox="0 0 ${VIEWBOX} ${VIEWBOX}" preserveAspectRatio="none">
|
|
132
|
-
<defs>
|
|
133
|
-
<filter id="wave-glow" x="-20%" y="-20%" width="140%" height="140%">
|
|
134
|
-
<feGaussianBlur stdDeviation="1.6" result="blur" />
|
|
135
|
-
<feMerge>
|
|
136
|
-
<feMergeNode in="blur" />
|
|
137
|
-
<feMergeNode in="SourceGraphic" />
|
|
138
|
-
</feMerge>
|
|
139
|
-
</filter>
|
|
140
|
-
</defs>
|
|
141
|
-
<g filter="url(#wave-glow)">${wavePathsMarkup}</g>
|
|
142
|
-
</svg>
|
|
143
|
-
<ai-halo-overlay active border-size="2" glow-opacity="0.5" glow-spread="55"></ai-halo-overlay>
|
|
144
|
-
</div>
|
|
145
|
-
`,
|
|
146
|
-
styles: css `
|
|
147
|
-
:host {
|
|
148
|
-
display: inline-block;
|
|
149
|
-
width: var(--waves-size, ${WAVES_DEFAULT_SIZE_CSS});
|
|
150
|
-
height: var(--waves-size, ${WAVES_DEFAULT_SIZE_CSS});
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
.window {
|
|
154
|
-
position: relative;
|
|
155
|
-
width: 100%;
|
|
156
|
-
height: 100%;
|
|
157
|
-
border-radius: 50%;
|
|
158
|
-
overflow: hidden;
|
|
159
|
-
background: radial-gradient(circle at 50% 32%, #2b3140 0%, #11141c 55%, #05070c 100%);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
.waves {
|
|
163
|
-
position: absolute;
|
|
164
|
-
inset: 0;
|
|
165
|
-
width: 100%;
|
|
166
|
-
height: 100%;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
.wave {
|
|
170
|
-
fill: none;
|
|
171
|
-
stroke-width: 2;
|
|
172
|
-
stroke-linecap: round;
|
|
173
|
-
stroke-linejoin: round;
|
|
174
|
-
}
|
|
175
|
-
`,
|
|
176
|
-
})
|
|
177
|
-
], AiWavesIndicator);
|
|
178
|
-
export { AiWavesIndicator };
|
|
179
|
-
// Ensure the halo overlay used for the ring is registered alongside this component.
|
|
180
|
-
avoidTreeShaking(AiHaloOverlay);
|