@usereq/widget 0.2.25 → 1.0.0-experimental.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.
@@ -1,682 +0,0 @@
1
- import React from "react";
2
- import { createRoot, type Root } from "react-dom/client";
3
- import {
4
- DEFAULT_WIDGET_APPEARANCE,
5
- DEFAULT_WIDGET_PRESET,
6
- normalizeWidgetPlacement,
7
- normalizeWidgetPreset,
8
- normalizeWidgetVariant,
9
- type WidgetAppearance,
10
- type WidgetMessage,
11
- type WidgetPlacement,
12
- type WidgetPreset,
13
- type WidgetSessionConfig,
14
- type WidgetSessionState,
15
- type WidgetVariant,
16
- } from "../types";
17
- import {
18
- normalizeWidgetMobileHeight,
19
- widgetTriggerRuleKey,
20
- } from "../shared/widget-config";
21
- import { WidgetRuntime, type WidgetRuntimeStatus } from "../renderer/index";
22
- import { buildAssistantMessageRevealSteps } from "../chat-widget/message-reveal";
23
- import { DEFAULT_STOP_CONVERSATION_PROMPT } from "../shared/stop-confirmation";
24
- import {
25
- bootstrapWidget,
26
- resetWidgetSession,
27
- submitWidgetStopConfirmation,
28
- submitWidgetMessage,
29
- } from "../runtime/bootstrap";
30
- import { getWidgetShadowCss } from "../shared/shadow-css";
31
- import { WIDGET_SHADOW_THEME_CSS } from "../shared/shadow-theme";
32
-
33
- type WidgetAppearanceAttributes = Partial<WidgetAppearance>;
34
-
35
- export class AgentWidgetElement extends HTMLElement {
36
- static observedAttributes = [
37
- "agent-id",
38
- "mode",
39
- "variant",
40
- "preset",
41
- "placement",
42
- "avatar-orb-color-1",
43
- "avatar-orb-color-2",
44
- "action-text",
45
- ];
46
-
47
- private shadowRootRef: ShadowRoot;
48
- private hostStyleElement: HTMLStyleElement;
49
- private shadowStyleElement: HTMLStyleElement;
50
- private mountElement: HTMLDivElement;
51
- private root: Root;
52
- private agentId = "";
53
- private mode: "embed" | "preview" = "embed";
54
- private variant: string | null = null;
55
- private preset: string | null = null;
56
- private placement: string | null = null;
57
- private appearanceAttributes: WidgetAppearanceAttributes = {};
58
- private open = false;
59
- private status: WidgetRuntimeStatus = "idle";
60
- private sessionConfig: WidgetSessionConfig | null = null;
61
- private sessionState: WidgetSessionState | null = null;
62
- private messages: WidgetMessage[] = [];
63
- private widgetTitle = "Assistant";
64
- private welcomeMessage: string | null = null;
65
- private errorMessage: string | null = null;
66
- private bootstrapPromise: Promise<void> | null = null;
67
- private bootstrapVersion = 0;
68
- private sendVersion = 0;
69
- private confirmationVersion = 0;
70
- private bootstrapPhase: "idle" | "booting" | "ready" | "blocked" = "idle";
71
- // Back-to-back send support. The composer stays enabled while the agent
72
- // is replying; new submissions land here and are drained sequentially by
73
- // `sendMessage`. Each entry carries the optimistic bubble id so failures
74
- // can yank exactly the right row.
75
- private pendingQueue: Array<{ content: string; optimisticId: string }> = [];
76
- private draining = false;
77
-
78
- constructor() {
79
- super();
80
- this.shadowRootRef = this.attachShadow({ mode: "open" });
81
- this.hostStyleElement = document.createElement("style");
82
- this.hostStyleElement.textContent = `
83
- ${WIDGET_SHADOW_THEME_CSS}
84
-
85
- :host {
86
- display: block;
87
- box-sizing: border-box;
88
- width: 100%;
89
- }
90
-
91
- :host([mode="preview"]) {
92
- position: relative;
93
- min-height: 720px;
94
- }
95
- `;
96
- this.shadowStyleElement = document.createElement("style");
97
- this.shadowStyleElement.textContent = getWidgetShadowCss() ?? "";
98
- this.mountElement = document.createElement("div");
99
- this.mountElement.style.display = "block";
100
- this.mountElement.style.width = "100%";
101
- this.mountElement.style.height = "100%";
102
- this.shadowRootRef.append(
103
- this.hostStyleElement,
104
- this.shadowStyleElement,
105
- this.mountElement,
106
- );
107
- this.root = createRoot(this.mountElement);
108
- }
109
-
110
- connectedCallback() {
111
- this.syncAttributes();
112
- this.renderWidget();
113
- if (this.agentId) {
114
- void this.ensureBootstrap();
115
- }
116
- }
117
-
118
- disconnectedCallback() {
119
- this.bootstrapPromise = null;
120
- this.root.unmount();
121
- }
122
-
123
- attributeChangedCallback(
124
- name?: string,
125
- oldValue?: string | null,
126
- newValue?: string | null,
127
- ) {
128
- this.syncAttributes();
129
- if (name === "agent-id" && oldValue !== newValue) {
130
- this.clearAgentState();
131
- }
132
- this.renderWidget();
133
- if (name === "agent-id" && this.agentId) {
134
- void this.ensureBootstrap();
135
- }
136
- }
137
-
138
- private syncAttributes() {
139
- this.agentId = this.getAttribute("agent-id")?.trim() ?? "";
140
- this.mode = normalizeWidgetMode(this.getAttribute("mode"));
141
- this.variant = this.getAttribute("variant");
142
- this.preset = this.getAttribute("preset");
143
- this.placement = this.getAttribute("placement");
144
- this.appearanceAttributes = parseAppearanceAttributes(this);
145
- }
146
-
147
- private getResolvedPlacement(): WidgetPlacement {
148
- return normalizeWidgetPlacement(
149
- this.placement ?? this.sessionConfig?.widgetConfig.widgetPlacement ?? "bottom-right",
150
- );
151
- }
152
-
153
- private getResolvedVariant(): WidgetVariant {
154
- return normalizeWidgetVariant(
155
- this.variant ?? this.sessionConfig?.widgetConfig.widgetVariant ?? "chatbar",
156
- );
157
- }
158
-
159
- private getResolvedPreset(): WidgetPreset {
160
- return normalizeWidgetPreset(
161
- this.preset ??
162
- this.sessionConfig?.widgetConfig.widgetPreset ??
163
- DEFAULT_WIDGET_PRESET,
164
- );
165
- }
166
-
167
- private getResolvedAppearance(): WidgetAppearance {
168
- const base =
169
- this.sessionConfig?.widgetConfig.widgetAppearance ?? DEFAULT_WIDGET_APPEARANCE;
170
-
171
- // Spread first, then apply the three attribute-overridable fields on top.
172
- // Only those three are exposed as HTML attributes; every other token
173
- // (surface colors, brand, text) comes from the agent config and must
174
- // pass through untouched — rebuilding a fixed-key object here is what
175
- // used to drop a customer's saved theme on the floor.
176
- return {
177
- ...base,
178
- avatarOrbColor1:
179
- this.appearanceAttributes.avatarOrbColor1?.trim() ||
180
- base.avatarOrbColor1,
181
- avatarOrbColor2:
182
- this.appearanceAttributes.avatarOrbColor2?.trim() ||
183
- base.avatarOrbColor2,
184
- actionText:
185
- this.appearanceAttributes.actionText?.trim() || base.actionText,
186
- };
187
- }
188
-
189
- private getWidgetTitle(): string {
190
- return this.sessionConfig?.widgetConfig.name ?? this.widgetTitle;
191
- }
192
-
193
- private getAgentAvatarUrl(): string | null {
194
- return this.sessionConfig?.widgetConfig.agentAvatarUrl ?? null;
195
- }
196
-
197
- private getWelcomeMessage(): string | null {
198
- return this.sessionConfig?.widgetConfig.welcomeMessage ?? this.welcomeMessage;
199
- }
200
-
201
- private getSpotlights(): string[] {
202
- return this.sessionConfig?.widgetConfig.spotlightMessages ?? [];
203
- }
204
-
205
- private getCtaLink(): string | null {
206
- return this.sessionConfig?.widgetConfig.ctaLink ?? null;
207
- }
208
-
209
- private clearAgentState() {
210
- this.sendVersion += 1;
211
- this.confirmationVersion += 1;
212
- this.bootstrapVersion += 1;
213
- this.bootstrapPhase = "idle";
214
- this.bootstrapPromise = null;
215
- this.sessionConfig = null;
216
- this.sessionState = null;
217
- this.messages = [];
218
- this.widgetTitle = "Assistant";
219
- this.welcomeMessage = null;
220
- this.errorMessage = null;
221
- this.status = "idle";
222
- // Bumping sendVersion above invalidates the in-flight drain; reset
223
- // the queue + flag so the next session starts fresh.
224
- this.pendingQueue = [];
225
- this.draining = false;
226
- }
227
-
228
- private renderWidget() {
229
- if (
230
- this.bootstrapPhase !== "ready" ||
231
- this.sessionConfig == null ||
232
- this.sessionState == null
233
- ) {
234
- this.root.render(null);
235
- return;
236
- }
237
-
238
- const appearance = this.getResolvedAppearance();
239
- const placement = this.getResolvedPlacement();
240
- const variant = this.getResolvedVariant();
241
- const preset = this.getResolvedPreset();
242
- const behavior = this.sessionConfig?.widgetConfig.widgetBehavior;
243
- const alwaysOpen = behavior?.alwaysOpen === true;
244
-
245
- this.root.render(
246
- React.createElement(WidgetRuntime, {
247
- key: `${this.agentId}:${widgetTriggerRuleKey(
248
- this.sessionConfig?.widgetConfig.triggerRule,
249
- )}`,
250
- mode: this.mode,
251
- agentId: this.agentId,
252
- variant,
253
- preset,
254
- placement,
255
- appearance,
256
- agentAvatarUrl: this.getAgentAvatarUrl(),
257
- widgetTitle: this.getWidgetTitle(),
258
- welcomeMessage: this.getWelcomeMessage(),
259
- spotlights: this.getSpotlights(),
260
- ctaLink: this.getCtaLink(),
261
- mobileHeight: normalizeWidgetMobileHeight(
262
- this.sessionConfig?.widgetConfig.mobileHeight,
263
- ),
264
- open: this.open,
265
- alwaysOpen,
266
- status: this.status,
267
- messages: this.messages,
268
- errorMessage: this.errorMessage,
269
- triggerRule: this.sessionConfig?.widgetConfig.triggerRule ?? null,
270
- // Lazy session: no "Start a chat" gate. The composer is live from
271
- // the moment the panel opens; the conversation is created on the
272
- // server the first time the user actually sends something.
273
- emptyAction: undefined,
274
- onStopConversation:
275
- this.sessionState?.conversationId != null
276
- ? () => void this.handleStopConversation()
277
- : undefined,
278
- onOpenChange: (nextOpen: boolean) => void this.handleOpenChange(nextOpen),
279
- onSendMessage: (content: string) => void this.sendMessage(content),
280
- onConfirmationDecision: (confirmationId: string, accepted: boolean) =>
281
- void this.handleConfirmationDecision(confirmationId, accepted),
282
- // Portal directly into the shadow root — matches the legacy
283
- // `agents-monorepo` widget exactly. ShadowRoot is a DocumentFragment,
284
- // which Radix Dialog accepts as `container`. The earlier `portalElement`
285
- // wrapper added a `pointer-events: none` ancestor that interfered with
286
- // the Dialog overlay/content's own event handling.
287
- portalContainer: this.shadowRootRef,
288
- }),
289
- );
290
- }
291
-
292
- private async ensureBootstrap() {
293
- if (this.bootstrapPromise) {
294
- return this.bootstrapPromise;
295
- }
296
-
297
- const runVersion = ++this.bootstrapVersion;
298
- this.bootstrapPromise = (async () => {
299
- if (!this.agentId) {
300
- this.status = "error";
301
- this.errorMessage = "Missing agent id";
302
- this.renderWidget();
303
- return;
304
- }
305
-
306
- this.bootstrapPhase = "booting";
307
- this.status = "booting";
308
- this.errorMessage = null;
309
- this.renderWidget();
310
-
311
- try {
312
- const state = await bootstrapWidget({
313
- agentId: this.agentId,
314
- pageUrl: window.location.href,
315
- referrer: document.referrer || undefined,
316
- });
317
-
318
- if (runVersion !== this.bootstrapVersion) {
319
- return;
320
- }
321
-
322
- this.sessionConfig = {
323
- sessionToken: state.session.sessionToken,
324
- expiresAt: state.session.expiresAt,
325
- widgetConfig: state.session.widgetConfig,
326
- };
327
- this.sessionState = state.session;
328
- this.messages = state.messages;
329
- this.widgetTitle = state.session.widgetConfig.name;
330
- this.welcomeMessage = state.session.widgetConfig.welcomeMessage;
331
- this.status = "ready";
332
- this.bootstrapPhase = "ready";
333
- // Lazy session: when the visitor doesn't already have a running
334
- // conversation, seed a client-side welcome bubble from the boot
335
- // config so the panel doesn't open on a blank empty state. The
336
- // real conversation is only created server-side once they type.
337
- this.seedClientWelcomeIfNeeded();
338
- // Apply the agent's configured open-state on mount. `alwaysOpen`
339
- // wins (the panel is pinned regardless), and `defaultOpen` opens it
340
- // once if the visitor hasn't already interacted with the launcher.
341
- const behavior = state.session.widgetConfig.widgetBehavior;
342
- if (behavior?.alwaysOpen || behavior?.defaultOpen) {
343
- this.open = true;
344
- }
345
- this.renderWidget();
346
- } catch (error) {
347
- if (runVersion !== this.bootstrapVersion) {
348
- return;
349
- }
350
-
351
- this.status = "error";
352
- this.bootstrapPhase = "blocked";
353
- this.errorMessage =
354
- error instanceof Error ? error.message : "Failed to start widget";
355
- this.renderWidget();
356
- }
357
- })().finally(() => {
358
- if (runVersion === this.bootstrapVersion) {
359
- this.bootstrapPromise = null;
360
- }
361
- });
362
-
363
- return this.bootstrapPromise;
364
- }
365
-
366
- /**
367
- * Entry point for user-typed sends. Drops the optimistic bubble in
368
- * immediately so the user sees their own backlog, then either kicks off
369
- * the drain loop (if idle) or appends to `pendingQueue` (if a prior send
370
- * is still mid-stream). The drain loop runs at most one POST in flight
371
- * at a time — the server-side session memory expects sequential turns,
372
- * and the AI engineer confirmed parallel requests are *possible* but
373
- * the answers would interleave out-of-order on the wire.
374
- */
375
- private async sendMessage(content: string) {
376
- const trimmedContent = content.trim();
377
- // Lazy session: no `conversationId` check here. If the visitor is
378
- // sending their very first message, `submitWidgetMessage` will call
379
- // POST /conversations/public/start under the hood before posting.
380
- if (!trimmedContent || !this.sessionState) return;
381
-
382
- const optimisticMessageId = `optimistic:${Date.now()}:${Math.random()
383
- .toString(36)
384
- .slice(2, 8)}`;
385
- const optimisticMessage: WidgetMessage = {
386
- id: optimisticMessageId,
387
- // Empty when no conversation exists yet — the real id lands on the
388
- // server row we swap in from `submitWidgetMessage`'s response.
389
- conversationId: this.sessionState.conversationId ?? "",
390
- role: "user",
391
- content: trimmedContent,
392
- createdAt: new Date().toISOString(),
393
- };
394
-
395
- this.errorMessage = null;
396
- this.messages = [...this.messages, optimisticMessage];
397
- this.renderWidget();
398
-
399
- // Drain already running → just join the queue. The drainer will
400
- // consume this entry as soon as the in-flight POST + reveal settle.
401
- if (this.draining) {
402
- this.pendingQueue.push({
403
- content: trimmedContent,
404
- optimisticId: optimisticMessageId,
405
- });
406
- return;
407
- }
408
-
409
- this.draining = true;
410
- this.status = "sending";
411
- this.renderWidget();
412
-
413
- const runVersion = this.sendVersion;
414
- let succeeded = true;
415
-
416
- try {
417
- await this.processSend(trimmedContent, optimisticMessageId, runVersion);
418
- while (this.pendingQueue.length > 0 && runVersion === this.sendVersion) {
419
- const next = this.pendingQueue.shift()!;
420
- await this.processSend(next.content, next.optimisticId, runVersion);
421
- }
422
- } catch {
423
- succeeded = false;
424
- if (runVersion === this.sendVersion) {
425
- // Drop the rest of the backlog — each queued message expects the
426
- // server to have already consumed the prior turn, which didn't
427
- // happen. Leaving them queued would silently fire mid-failure.
428
- const failedIds = new Set(
429
- this.pendingQueue.map((entry) => entry.optimisticId),
430
- );
431
- this.pendingQueue = [];
432
- this.messages = this.messages.filter((m) => !failedIds.has(m.id));
433
- // `processSend` already set status="error" + errorMessage; render
434
- // once more so the cleared queue is visible.
435
- this.renderWidget();
436
- }
437
- } finally {
438
- this.draining = false;
439
- if (succeeded && runVersion === this.sendVersion) {
440
- this.status = "ready";
441
- this.renderWidget();
442
- }
443
- }
444
- }
445
-
446
- /**
447
- * One round-trip: POST → swap optimistic → stagger assistant reveal.
448
- * Throws on failure so the outer drainer can clear the backlog. The
449
- * `runVersion` guard short-circuits late state writes if a hard reset
450
- * (agent-id change, conversation reset) bumped `sendVersion` mid-drain.
451
- */
452
- private async processSend(
453
- content: string,
454
- optimisticId: string,
455
- runVersion: number,
456
- ) {
457
- try {
458
- const result = await submitWidgetMessage({
459
- agentId: this.agentId,
460
- content,
461
- });
462
- if (runVersion !== this.sendVersion) return;
463
- this.sessionState = result.session;
464
-
465
- // Lazy-start swap: when this was the first send, `submitWidgetMessage`
466
- // created the conversation server-side and the server inserted its
467
- // own welcome message row. Replace the placeholder client-welcome
468
- // bubble with the real server row so ids/timestamps match the DB.
469
- if (result.welcomeMessage) {
470
- const clientWelcomeId = this.getClientWelcomeId();
471
- this.messages = this.messages.map((m) =>
472
- m.id === clientWelcomeId
473
- ? {
474
- id: result.welcomeMessage!.id,
475
- conversationId: result.conversationId,
476
- role: "assistant",
477
- content: result.welcomeMessage!.content,
478
- createdAt: result.welcomeMessage!.createdAt,
479
- }
480
- : m,
481
- );
482
- this.renderWidget();
483
- }
484
-
485
- const revealSteps = buildAssistantMessageRevealSteps(
486
- result.assistantMessages.map((message) => ({
487
- id: message.id,
488
- content: message.content,
489
- createdAt: message.createdAt,
490
- })),
491
- {
492
- initialDelayMs: 0,
493
- typingHoldMs: 1260,
494
- interMessageDelayMs: 1520,
495
- interMessageDelayJitterMs: 100,
496
- },
497
- );
498
-
499
- for (const step of revealSteps) {
500
- await new Promise((resolve) =>
501
- window.setTimeout(resolve, step.delayMs),
502
- );
503
- if (runVersion !== this.sendVersion) return;
504
- const dto = step.message;
505
- this.messages = [
506
- ...this.messages,
507
- {
508
- id: dto.id,
509
- conversationId: result.conversationId,
510
- role: "assistant",
511
- content: dto.content,
512
- createdAt: dto.createdAt,
513
- },
514
- ];
515
- this.renderWidget();
516
- }
517
- } catch (error) {
518
- if (runVersion !== this.sendVersion) {
519
- // The hard reset path already cleared state — swallow.
520
- return;
521
- }
522
- this.messages = this.messages.filter((m) => m.id !== optimisticId);
523
- this.status = "error";
524
- this.errorMessage =
525
- error instanceof Error ? error.message : "Failed to send message";
526
- this.renderWidget();
527
- throw error;
528
- }
529
- }
530
-
531
- private async handleOpenChange(nextOpen: boolean) {
532
- this.open = nextOpen;
533
- this.renderWidget();
534
-
535
- if (this.open && (this.status === "idle" || !this.sessionState)) {
536
- await this.ensureBootstrap();
537
- }
538
- }
539
-
540
- private getClientWelcomeId(): string {
541
- return `client-welcome:${this.agentId}`;
542
- }
543
-
544
- /**
545
- * Lazy session seeding. When bootstrap finishes with no live conversation
546
- * and no rehydrated transcript, drop a synthetic assistant bubble carrying
547
- * the boot-config welcome copy into `this.messages`. Skipped when there's
548
- * already a transcript (rehydrated session) or no welcome copy configured.
549
- * The bubble's id is stable (`client-welcome:{agentId}`) so `processSend`
550
- * can swap it for the real server row after the first successful send.
551
- */
552
- private seedClientWelcomeIfNeeded() {
553
- if (this.messages.length > 0) return;
554
- if (this.sessionState?.conversationId) return;
555
- const welcome = this.getWelcomeMessage();
556
- if (!welcome) return;
557
- this.messages = [
558
- {
559
- id: this.getClientWelcomeId(),
560
- conversationId: "",
561
- role: "assistant",
562
- content: welcome,
563
- createdAt: new Date().toISOString(),
564
- },
565
- ];
566
- }
567
-
568
- private async handleStopConversation() {
569
- if (!this.sessionState?.conversationId) {
570
- return;
571
- }
572
-
573
- const confirmationId = crypto.randomUUID();
574
- const runVersion = ++this.confirmationVersion;
575
-
576
- this.status = "sending";
577
- this.errorMessage = null;
578
- this.renderWidget();
579
-
580
- try {
581
- const result = await submitWidgetStopConfirmation({
582
- agentId: this.agentId,
583
- confirmationId,
584
- prompt: DEFAULT_STOP_CONVERSATION_PROMPT,
585
- });
586
-
587
- if (runVersion !== this.confirmationVersion) {
588
- return;
589
- }
590
-
591
- this.sessionState = result.session;
592
- this.messages = [...this.messages, result.confirmationMessage];
593
- this.status = "ready";
594
- this.renderWidget();
595
- } catch (error) {
596
- if (runVersion !== this.confirmationVersion) {
597
- return;
598
- }
599
- this.status = "error";
600
- this.errorMessage =
601
- error instanceof Error ? error.message : "Failed to stop conversation";
602
- this.renderWidget();
603
- }
604
- }
605
-
606
- private async handleConfirmationDecision(
607
- confirmationId: string,
608
- accepted: boolean,
609
- ) {
610
- if (!this.sessionState?.conversationId) {
611
- return;
612
- }
613
-
614
- const runVersion = ++this.confirmationVersion;
615
- this.status = "sending";
616
- this.errorMessage = null;
617
- this.renderWidget();
618
-
619
- try {
620
- const result = await submitWidgetStopConfirmation({
621
- agentId: this.agentId,
622
- confirmationId,
623
- decision: accepted ? "accepted" : "rejected",
624
- });
625
-
626
- if (runVersion !== this.confirmationVersion) {
627
- return;
628
- }
629
-
630
- this.sessionState = result.session;
631
- this.messages = [...this.messages, result.confirmationMessage];
632
- this.renderWidget();
633
-
634
- if (accepted) {
635
- window.setTimeout(() => {
636
- if (runVersion !== this.confirmationVersion) {
637
- return;
638
- }
639
- void this.handleReset();
640
- }, 0);
641
- } else {
642
- this.status = "ready";
643
- this.renderWidget();
644
- }
645
- } catch (error) {
646
- if (runVersion !== this.confirmationVersion) {
647
- return;
648
- }
649
- this.status = "error";
650
- this.errorMessage =
651
- error instanceof Error ? error.message : "Failed to update confirmation";
652
- this.renderWidget();
653
- }
654
- }
655
-
656
- private handleReset = async () => {
657
- this.sendVersion += 1;
658
- await resetWidgetSession(this.agentId);
659
- this.clearAgentState();
660
- this.open = true;
661
- this.renderWidget();
662
- await this.ensureBootstrap();
663
- };
664
- }
665
-
666
- function parseAppearanceAttributes(
667
- element: HTMLElement,
668
- ): WidgetAppearanceAttributes {
669
- const avatarOrbColor1 = element.getAttribute("avatar-orb-color-1");
670
- const avatarOrbColor2 = element.getAttribute("avatar-orb-color-2");
671
- const actionText = element.getAttribute("action-text");
672
-
673
- return {
674
- avatarOrbColor1: avatarOrbColor1?.trim() || undefined,
675
- avatarOrbColor2: avatarOrbColor2?.trim() || undefined,
676
- actionText: actionText?.trim() || undefined,
677
- };
678
- }
679
-
680
- function normalizeWidgetMode(value: string | null): "embed" | "preview" {
681
- return value === "preview" ? "preview" : "embed";
682
- }
package/src/embed.ts DELETED
@@ -1,8 +0,0 @@
1
- import widgetShadowCss from "@usereq/ui/globals.css?inline";
2
- import { setWidgetShadowCss } from "./shared/shadow-css";
3
- import { registerWidgetElement } from "./register";
4
-
5
- setWidgetShadowCss(widgetShadowCss);
6
- registerWidgetElement();
7
-
8
- export {};
package/src/index.ts DELETED
@@ -1,9 +0,0 @@
1
- export * from "./shared/widget-config";
2
- export * from "./renderer/index";
3
- export * from "./types";
4
- export * from "./shared/shadow-css";
5
- export * from "./register";
6
-
7
- import { registerWidgetElement } from "./register";
8
-
9
- registerWidgetElement();