@agent-native/toolkit 0.210.0-nightly-20261019153056 → 0.210.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/LICENSE +21 -0
  2. package/dist/app/i18n/catalogs/ar-SA.d.ts.map +1 -1
  3. package/dist/app/i18n/catalogs/ar-SA.js +12 -3
  4. package/dist/app/i18n/catalogs/ar-SA.js.map +1 -1
  5. package/dist/app/i18n/catalogs/de-DE.d.ts.map +1 -1
  6. package/dist/app/i18n/catalogs/de-DE.js +12 -3
  7. package/dist/app/i18n/catalogs/de-DE.js.map +1 -1
  8. package/dist/app/i18n/catalogs/en-US.d.ts +12 -3
  9. package/dist/app/i18n/catalogs/en-US.d.ts.map +1 -1
  10. package/dist/app/i18n/catalogs/en-US.js +12 -3
  11. package/dist/app/i18n/catalogs/en-US.js.map +1 -1
  12. package/dist/app/i18n/catalogs/es-ES.d.ts.map +1 -1
  13. package/dist/app/i18n/catalogs/es-ES.js +12 -3
  14. package/dist/app/i18n/catalogs/es-ES.js.map +1 -1
  15. package/dist/app/i18n/catalogs/fr-FR.d.ts.map +1 -1
  16. package/dist/app/i18n/catalogs/fr-FR.js +12 -3
  17. package/dist/app/i18n/catalogs/fr-FR.js.map +1 -1
  18. package/dist/app/i18n/catalogs/hi-IN.d.ts.map +1 -1
  19. package/dist/app/i18n/catalogs/hi-IN.js +12 -3
  20. package/dist/app/i18n/catalogs/hi-IN.js.map +1 -1
  21. package/dist/app/i18n/catalogs/ja-JP.d.ts.map +1 -1
  22. package/dist/app/i18n/catalogs/ja-JP.js +12 -3
  23. package/dist/app/i18n/catalogs/ja-JP.js.map +1 -1
  24. package/dist/app/i18n/catalogs/ko-KR.d.ts.map +1 -1
  25. package/dist/app/i18n/catalogs/ko-KR.js +12 -3
  26. package/dist/app/i18n/catalogs/ko-KR.js.map +1 -1
  27. package/dist/app/i18n/catalogs/pt-BR.d.ts.map +1 -1
  28. package/dist/app/i18n/catalogs/pt-BR.js +12 -3
  29. package/dist/app/i18n/catalogs/pt-BR.js.map +1 -1
  30. package/dist/app/i18n/catalogs/zh-CN.d.ts.map +1 -1
  31. package/dist/app/i18n/catalogs/zh-CN.js +12 -3
  32. package/dist/app/i18n/catalogs/zh-CN.js.map +1 -1
  33. package/dist/app/i18n/catalogs/zh-TW.d.ts.map +1 -1
  34. package/dist/app/i18n/catalogs/zh-TW.js +12 -3
  35. package/dist/app/i18n/catalogs/zh-TW.js.map +1 -1
  36. package/dist/app/onboarding/FirstRunOnboarding.d.ts.map +1 -1
  37. package/dist/app/onboarding/FirstRunOnboarding.js +53 -33
  38. package/dist/app/onboarding/FirstRunOnboarding.js.map +1 -1
  39. package/dist/app/sharing/ShareButton.js +1 -1
  40. package/dist/app/sharing/ShareButton.js.map +1 -1
  41. package/dist/theme/resource-icons.css +18 -18
  42. package/package.json +4 -4
  43. package/src/app/i18n/catalogs/ar-SA.ts +15 -4
  44. package/src/app/i18n/catalogs/de-DE.ts +15 -5
  45. package/src/app/i18n/catalogs/en-US.ts +15 -4
  46. package/src/app/i18n/catalogs/es-ES.ts +15 -6
  47. package/src/app/i18n/catalogs/fr-FR.ts +15 -6
  48. package/src/app/i18n/catalogs/hi-IN.ts +15 -4
  49. package/src/app/i18n/catalogs/ja-JP.ts +15 -4
  50. package/src/app/i18n/catalogs/ko-KR.ts +15 -4
  51. package/src/app/i18n/catalogs/pt-BR.ts +15 -6
  52. package/src/app/i18n/catalogs/zh-CN.ts +15 -4
  53. package/src/app/i18n/catalogs/zh-TW.ts +15 -4
  54. package/src/app/onboarding/FirstRunOnboarding.spec.tsx +44 -6
  55. package/src/app/onboarding/FirstRunOnboarding.tsx +196 -59
  56. package/src/app/sharing/ShareButton.spec.tsx +34 -0
  57. package/src/app/sharing/ShareButton.tsx +7 -1
  58. package/src/theme/resource-icons.css +18 -18
@@ -28,12 +28,25 @@ import type {
28
28
  OnboardingCapability,
29
29
  } from "@agent-native/core/onboarding/types";
30
30
  import { Badge } from "@agent-native/toolkit/ui/badge";
31
+ import { Button } from "@agent-native/toolkit/ui/button";
32
+ import {
33
+ Popover,
34
+ PopoverContent,
35
+ PopoverTrigger,
36
+ } from "@agent-native/toolkit/ui/popover";
31
37
  import { Skeleton } from "@agent-native/toolkit/ui/skeleton";
38
+ import {
39
+ Tooltip,
40
+ TooltipContent,
41
+ TooltipProvider,
42
+ TooltipTrigger,
43
+ } from "@agent-native/toolkit/ui/tooltip";
32
44
  import { cn } from "@agent-native/toolkit/utils";
33
45
  import {
34
46
  IconArrowRight,
35
47
  IconChevronDown,
36
48
  IconChevronUp,
49
+ IconHelpCircle,
37
50
  IconKey,
38
51
  IconLoader2,
39
52
  } from "@tabler/icons-react";
@@ -206,6 +219,20 @@ export function FirstRunOnboarding({
206
219
  const canTrackOnboardingScreen =
207
220
  (!loading && profile !== null) || canRenderRoleWithoutProfile;
208
221
  const setupSkippable = profile?.appId === "clips";
222
+ const [setupExperimentDecision, setSetupExperimentDecision] = useState<
223
+ boolean | null
224
+ >(null);
225
+ const setupVariant = useMemo(
226
+ () =>
227
+ (previewMode && getPreviewFirstRunSetupVariant(window.location.search)) ||
228
+ assignFirstRunSetupVariant(),
229
+ [previewMode],
230
+ );
231
+ // The credits arm offers Skip in every app, so analytics must mark the choice step optional there too.
232
+ const choiceSkippable =
233
+ setupSkippable ||
234
+ (setupVariant === "credits" &&
235
+ (previewMode || setupExperimentDecision === true));
209
236
  const [extensionPlacement, setExtensionPlacement] =
210
237
  useState<FirstRunExtensionPlacement>("after-setup");
211
238
  const [extensionIndex, setExtensionIndex] = useState(0);
@@ -254,7 +281,7 @@ export function FirstRunOnboarding({
254
281
  extensionPlacement,
255
282
  extensionIndex,
256
283
  extensionStepIndex,
257
- setupSkippable,
284
+ choiceSkippable,
258
285
  ).step_index ?? 0,
259
286
  );
260
287
  const progressWidth = `${Math.min(
@@ -263,15 +290,8 @@ export function FirstRunOnboarding({
263
290
  )}%`;
264
291
  const redesign = useFeatureFlagState(SETTINGS_REDESIGN_FLAG.key);
265
292
  const [moreInfoOpen, setMoreInfoOpen] = useState(false);
266
- const [setupExperimentDecision, setSetupExperimentDecision] = useState<
267
- boolean | null
268
- >(null);
269
- const setupVariant = useMemo(
270
- () =>
271
- (previewMode && getPreviewFirstRunSetupVariant(window.location.search)) ||
272
- assignFirstRunSetupVariant(),
273
- [previewMode],
274
- );
293
+ const [skipConfirmOpen, setSkipConfirmOpen] = useState(false);
294
+ const skipGoBackRef = useRef<HTMLButtonElement>(null);
275
295
  useEffect(() => {
276
296
  if (!previewMode || !previewStep) return;
277
297
  setScreen(previewStep === "references" ? "extension" : previewStep);
@@ -292,7 +312,7 @@ export function FirstRunOnboarding({
292
312
  extensionPlacement,
293
313
  stepExtensionIndex,
294
314
  stepIndex,
295
- setupSkippable,
315
+ choiceSkippable,
296
316
  ),
297
317
  );
298
318
  },
@@ -303,7 +323,7 @@ export function FirstRunOnboarding({
303
323
  extensionPlacement,
304
324
  extensionStepIndex,
305
325
  previewMode,
306
- setupSkippable,
326
+ choiceSkippable,
307
327
  ],
308
328
  );
309
329
  const trackFirstRunStepSkipped = useCallback(
@@ -322,7 +342,7 @@ export function FirstRunOnboarding({
322
342
  extensionPlacement,
323
343
  stepExtensionIndex,
324
344
  stepIndex,
325
- setupSkippable,
345
+ choiceSkippable,
326
346
  ),
327
347
  reason,
328
348
  });
@@ -334,7 +354,7 @@ export function FirstRunOnboarding({
334
354
  extensionPlacement,
335
355
  extensionStepIndex,
336
356
  previewMode,
337
- setupSkippable,
357
+ choiceSkippable,
338
358
  ],
339
359
  );
340
360
  const completionAttemptRef = useRef<{
@@ -417,8 +437,21 @@ export function FirstRunOnboarding({
417
437
  trackOnboardingEvent("onboarding_started", { flow: "first_run" });
418
438
  }
419
439
  }, [canTrackOnboardingScreen, firstRun, previewMode]);
440
+ // Both arms render a skeleton until the experiment decision is known, and the
441
+ // credits arm's skip depends on it, so the choice view waits for the decision
442
+ // and is sent once with its resolved optional flag. Without an assigned arm
443
+ // no decision is ever made, and the choice UI renders as is.
444
+ const choiceStepKnown =
445
+ screen !== "choice" ||
446
+ setupVariant === null ||
447
+ setupExperimentDecision !== null;
420
448
  useEffect(() => {
421
- if (previewMode || !firstRun || !canTrackOnboardingScreen) {
449
+ if (
450
+ previewMode ||
451
+ !firstRun ||
452
+ !canTrackOnboardingScreen ||
453
+ !choiceStepKnown
454
+ ) {
422
455
  stepViewRef.current = null;
423
456
  return;
424
457
  }
@@ -429,7 +462,7 @@ export function FirstRunOnboarding({
429
462
  extensionPlacement,
430
463
  extensionIndex,
431
464
  extensionStepIndex,
432
- setupSkippable,
465
+ choiceSkippable,
433
466
  );
434
467
  const key = [step.step_id, step.extension_id, step.step_index].join(":");
435
468
  if (stepViewRef.current?.key !== key) {
@@ -451,6 +484,7 @@ export function FirstRunOnboarding({
451
484
  firstRun,
452
485
  previewMode,
453
486
  canTrackOnboardingScreen,
487
+ choiceStepKnown,
454
488
  screen,
455
489
  ]);
456
490
  useEffect(() => {
@@ -472,7 +506,7 @@ export function FirstRunOnboarding({
472
506
  extensionPlacement,
473
507
  extensionIndex,
474
508
  extensionStepIndex,
475
- setupSkippable,
509
+ choiceSkippable,
476
510
  ),
477
511
  reason: "page_exit",
478
512
  });
@@ -489,7 +523,7 @@ export function FirstRunOnboarding({
489
523
  previewMode,
490
524
  canTrackOnboardingScreen,
491
525
  screen,
492
- setupSkippable,
526
+ choiceSkippable,
493
527
  ]);
494
528
  const beginBeforeSetup = useCallback(() => {
495
529
  if (beforeSetupExtensions.length === 0) {
@@ -892,7 +926,7 @@ export function FirstRunOnboarding({
892
926
  if (setupSkipStartedRef.current || completionInFlightRef.current) return;
893
927
  setupSkipStartedRef.current = true;
894
928
  trackFirstRunStepSkipped("choice");
895
- completionRedirectRef.current = "/record";
929
+ if (setupSkippable) completionRedirectRef.current = "/record";
896
930
  handleFinish(null);
897
931
  };
898
932
 
@@ -991,9 +1025,16 @@ export function FirstRunOnboarding({
991
1025
  );
992
1026
 
993
1027
  if (creditsEligible) {
994
- const linkClass =
995
- "rounded-sm underline underline-offset-2 transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-60";
996
1028
  const MoreInfoChevron = moreInfoOpen ? IconChevronUp : IconChevronDown;
1029
+ const toggleMoreInfo = () => {
1030
+ if (!moreInfoOpen && !previewMode) {
1031
+ trackOnboardingEvent("onboarding_more_info_opened", {
1032
+ flow: "first_run",
1033
+ step_id: "choice",
1034
+ });
1035
+ }
1036
+ setMoreInfoOpen((open) => !open);
1037
+ };
997
1038
  return (
998
1039
  <OnboardingShell
999
1040
  profile={profile}
@@ -1005,11 +1046,31 @@ export function FirstRunOnboarding({
1005
1046
  data-testid="first-run-credits-offer"
1006
1047
  className="mx-auto flex w-full flex-col items-center gap-5 pt-[max(0rem,6vh)] text-center"
1007
1048
  >
1008
- <h1 className="max-w-lg text-balance text-[28px] font-bold leading-tight tracking-[-0.02em] text-foreground">
1049
+ <h1
1050
+ className={cn(
1051
+ "text-balance text-[28px] font-bold leading-tight tracking-[-0.02em] text-foreground",
1052
+ profile.appId === "clips" ? "max-w-lg" : "max-w-sm",
1053
+ )}
1054
+ >
1009
1055
  {profile.appId === "clips"
1010
1056
  ? t("agentChat.onboarding.creditsTitleClips")
1011
1057
  : t("agentChat.onboarding.creditsTitle")}
1012
1058
  </h1>
1059
+ <p className="max-w-sm text-sm leading-6 text-muted-foreground">
1060
+ {t("agentChat.onboarding.creditsSubtitle")}{" "}
1061
+ <button
1062
+ type="button"
1063
+ data-testid="first-run-credits-learn-more"
1064
+ aria-expanded={moreInfoOpen}
1065
+ aria-controls={
1066
+ moreInfoOpen ? "first-run-credits-details" : undefined
1067
+ }
1068
+ className="rounded-sm underline underline-offset-2 transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
1069
+ onClick={toggleMoreInfo}
1070
+ >
1071
+ {t("agentChat.onboarding.creditsLearnMore")}
1072
+ </button>
1073
+ </p>
1013
1074
  <div className="flex w-full max-w-sm flex-col items-center gap-3">
1014
1075
  <button
1015
1076
  type="button"
@@ -1023,6 +1084,15 @@ export function FirstRunOnboarding({
1023
1084
  >
1024
1085
  {t("agentChat.onboarding.creditsActivate")}
1025
1086
  </button>
1087
+ <button
1088
+ type="button"
1089
+ data-testid="first-run-credits-connect-existing"
1090
+ className={cn(mutedButtonClass, "min-h-11 w-full text-sm")}
1091
+ onClick={() => handleBuilder(false)}
1092
+ disabled={connectFlow.connecting}
1093
+ >
1094
+ {t("agentChat.onboarding.builderExistingAccount")}
1095
+ </button>
1026
1096
  <p className="text-xs leading-5 text-muted-foreground">
1027
1097
  {t("agentChat.onboarding.creditsFinePrint")}{" "}
1028
1098
  <a
@@ -1046,31 +1116,16 @@ export function FirstRunOnboarding({
1046
1116
  </p>
1047
1117
  </div>
1048
1118
  {builderStatusError}
1049
- <div className="flex flex-wrap items-center justify-center gap-x-4 gap-y-2 text-xs text-muted-foreground">
1050
- <button
1051
- type="button"
1052
- data-testid="first-run-credits-connect-existing"
1053
- className={linkClass}
1054
- onClick={() => handleBuilder(false)}
1055
- disabled={connectFlow.connecting}
1056
- >
1057
- {t("agentChat.onboarding.creditsConnectExisting")}
1058
- </button>
1119
+ <div className="flex flex-wrap items-center justify-center gap-x-3 gap-y-2">
1059
1120
  <button
1060
1121
  type="button"
1061
1122
  data-testid="first-run-credits-more-info"
1062
1123
  aria-expanded={moreInfoOpen}
1063
- aria-controls="first-run-credits-details"
1064
- className="inline-flex min-h-8 items-center gap-1 rounded-full border border-border px-3 font-medium text-foreground transition-colors hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
1065
- onClick={() => {
1066
- if (!moreInfoOpen && !previewMode) {
1067
- trackOnboardingEvent("onboarding_more_info_opened", {
1068
- flow: "first_run",
1069
- step_id: "choice",
1070
- });
1071
- }
1072
- setMoreInfoOpen((open) => !open);
1073
- }}
1124
+ aria-controls={
1125
+ moreInfoOpen ? "first-run-credits-details" : undefined
1126
+ }
1127
+ className="inline-flex min-h-8 items-center gap-1 rounded-full border border-border px-3 text-xs font-medium text-foreground transition-colors hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
1128
+ onClick={toggleMoreInfo}
1074
1129
  >
1075
1130
  {t("agentChat.onboarding.creditsMoreInfo")}
1076
1131
  <MoreInfoChevron size={14} aria-hidden />
@@ -1083,16 +1138,78 @@ export function FirstRunOnboarding({
1083
1138
  className="mt-3 flex w-full max-w-3xl flex-col gap-6 text-left"
1084
1139
  >
1085
1140
  {setupCards}
1086
- {setupSkippable && (
1087
- <div className="flex flex-col items-center gap-1 text-center">
1088
- <p className="text-xs text-muted-foreground">
1089
- {t("agentChat.onboarding.creditsSkipBody")}
1090
- </p>
1091
- {setupSkipButton}
1092
- </div>
1093
- )}
1094
1141
  </div>
1095
1142
  )}
1143
+ <div className="fixed bottom-6 right-6 z-10">
1144
+ <Popover open={skipConfirmOpen} onOpenChange={setSkipConfirmOpen}>
1145
+ <PopoverTrigger asChild>
1146
+ <button
1147
+ type="button"
1148
+ data-testid="first-run-credits-skip"
1149
+ className="inline-flex min-h-6 items-center px-2 rounded-sm text-xs font-medium text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
1150
+ >
1151
+ {t("agentChat.onboarding.creditsSkip")}
1152
+ </button>
1153
+ </PopoverTrigger>
1154
+ <PopoverContent
1155
+ side="top"
1156
+ align="end"
1157
+ portalled={false}
1158
+ aria-labelledby="first-run-credits-skip-title"
1159
+ aria-describedby="first-run-credits-skip-body"
1160
+ className="w-96 max-w-[calc(100vw-2rem)] space-y-3 p-4 text-left"
1161
+ onOpenAutoFocus={(event) => {
1162
+ event.preventDefault();
1163
+ skipGoBackRef.current?.focus();
1164
+ }}
1165
+ >
1166
+ <div className="space-y-1">
1167
+ <p
1168
+ id="first-run-credits-skip-title"
1169
+ className="text-sm font-semibold text-foreground"
1170
+ >
1171
+ {t("agentChat.onboarding.creditsSkipConfirmTitle")}
1172
+ </p>
1173
+ <p
1174
+ id="first-run-credits-skip-body"
1175
+ className="text-xs leading-5 text-muted-foreground"
1176
+ >
1177
+ {t("agentChat.onboarding.creditsSkipConfirmBody")}
1178
+ </p>
1179
+ </div>
1180
+ <div className="flex flex-wrap items-center justify-between gap-2">
1181
+ <Button
1182
+ type="button"
1183
+ variant="ghost"
1184
+ size="sm"
1185
+ className="px-0 text-muted-foreground hover:bg-transparent hover:text-foreground"
1186
+ onClick={() => void handleOpenSettings()}
1187
+ >
1188
+ {t("agentChat.onboarding.creditsUseCustomKeys")}
1189
+ </Button>
1190
+ <div className="flex flex-wrap justify-end gap-2">
1191
+ <Button
1192
+ type="button"
1193
+ variant="secondary"
1194
+ size="sm"
1195
+ data-testid="first-run-credits-skip-confirm"
1196
+ onClick={skipSetup}
1197
+ >
1198
+ {t("agentChat.onboarding.creditsSkipAnyway")}
1199
+ </Button>
1200
+ <Button
1201
+ type="button"
1202
+ size="sm"
1203
+ ref={skipGoBackRef}
1204
+ onClick={() => setSkipConfirmOpen(false)}
1205
+ >
1206
+ {t("agentChat.onboarding.creditsSkipGoBack")}
1207
+ </Button>
1208
+ </div>
1209
+ </div>
1210
+ </PopoverContent>
1211
+ </Popover>
1212
+ </div>
1096
1213
  </div>
1097
1214
  </OnboardingShell>
1098
1215
  );
@@ -1285,15 +1402,35 @@ export function FirstRunOnboarding({
1285
1402
  {accountExists
1286
1403
  ? t("agentChat.onboarding.builderAccountExistsTitle")
1287
1404
  : provisioning
1288
- ? t("agentChat.onboarding.builderActivating")
1405
+ ? t("agentChat.onboarding.creditsActivating")
1289
1406
  : t("agentChat.onboarding.builderConnecting")}
1290
1407
  </h1>
1291
1408
  <p className="mt-2 text-sm text-muted-foreground">
1292
- {accountExists
1293
- ? t("agentChat.onboarding.builderAccountExistsDescription")
1294
- : provisioning
1295
- ? t("agentChat.onboarding.builderProvisioningDescription")
1296
- : t("agentChat.onboarding.builderConnectionDescription")}
1409
+ {accountExists ? (
1410
+ t("agentChat.onboarding.builderAccountExistsDescription")
1411
+ ) : provisioning ? (
1412
+ <>
1413
+ {t("agentChat.onboarding.builderProvisioningDescription")}
1414
+ <TooltipProvider>
1415
+ <Tooltip>
1416
+ <TooltipTrigger asChild>
1417
+ <button
1418
+ type="button"
1419
+ aria-label={t("agentChat.onboarding.creditsAboutLabel")}
1420
+ className="ml-0 inline-flex size-6 items-center justify-center rounded-full align-middle text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
1421
+ >
1422
+ <IconHelpCircle size={12} aria-hidden />
1423
+ </button>
1424
+ </TooltipTrigger>
1425
+ <TooltipContent side="top" className="max-w-xs text-xs">
1426
+ {t("agentChat.onboarding.creditsActivatingTooltip")}
1427
+ </TooltipContent>
1428
+ </Tooltip>
1429
+ </TooltipProvider>
1430
+ </>
1431
+ ) : (
1432
+ t("agentChat.onboarding.builderConnectionDescription")
1433
+ )}
1297
1434
  </p>
1298
1435
  {accountExists ? (
1299
1436
  <button
@@ -1341,7 +1478,7 @@ export function FirstRunOnboarding({
1341
1478
  <button
1342
1479
  type="button"
1343
1480
  data-testid="first-run-cancel-builder"
1344
- className={cn(secondaryButtonClass, "mt-4")}
1481
+ className="fixed bottom-6 left-6 inline-flex min-h-6 items-center px-2 rounded-sm text-xs font-medium text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
1345
1482
  onClick={() => {
1346
1483
  setBuilderCancelRequested(true);
1347
1484
  connectFlow.cancel();
@@ -1398,7 +1535,7 @@ export function FirstRunOnboarding({
1398
1535
  <button
1399
1536
  type="button"
1400
1537
  data-testid="first-run-back-to-choice"
1401
- className={cn(secondaryButtonClass, "mt-4")}
1538
+ className="fixed bottom-6 left-6 inline-flex min-h-6 items-center px-2 rounded-sm text-xs font-medium text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
1402
1539
  onClick={returnToSetupChoice}
1403
1540
  >
1404
1541
  {t("agentChat.onboarding.back")}
@@ -1298,6 +1298,40 @@ describe("ShareButton", () => {
1298
1298
  expect(container.textContent).toContain("second@builder.io");
1299
1299
  });
1300
1300
 
1301
+ it("keeps links placed at the bottom after the people and access sections in the tabbed layout", async () => {
1302
+ await act(async () => {
1303
+ root.render(
1304
+ <TooltipProvider>
1305
+ <QueryClientProvider client={queryClient}>
1306
+ <ShareButton
1307
+ resourceType="deck"
1308
+ resourceId="deck-1"
1309
+ defaultOpen
1310
+ shareUrl="https://slides.agent-native.com/deck/deck-1"
1311
+ shareUrlLabel="Editor link"
1312
+ secondaryShareUrl="https://slides.agent-native.com/p/deck-1"
1313
+ secondaryShareUrlLabel="Presentation link"
1314
+ shareUrlPlacement="bottom"
1315
+ peopleTabLabel="People"
1316
+ agentsTabLabel="Agents"
1317
+ agentTabContent={<button type="button">Copy agent prompt</button>}
1318
+ />
1319
+ </QueryClientProvider>
1320
+ </TooltipProvider>,
1321
+ );
1322
+ });
1323
+
1324
+ const links = Array.from(
1325
+ document.body.querySelectorAll<HTMLElement>("div.order-3"),
1326
+ ).find((el) => el.textContent?.includes("Editor link"));
1327
+ expect(links).toBeDefined();
1328
+ expect(links!.textContent).toContain("Presentation link");
1329
+ // The sections the links must follow carry lower orders in the same column.
1330
+ const column = links!.parentElement!;
1331
+ expect(column.querySelector(":scope > .order-1")).not.toBeNull();
1332
+ expect(column.querySelector(":scope > .order-2")).not.toBeNull();
1333
+ });
1334
+
1301
1335
  it("keeps quick copy separate from People and Agents tabs", async () => {
1302
1336
  const onCopy = vi.fn(async () => true);
1303
1337
  await act(async () => {
@@ -874,7 +874,13 @@ function SharePanel(
874
874
  </div>
875
875
  ) : null}
876
876
 
877
- {showShareLinks && shareUrlPlacement === "bottom" ? shareLinks : null}
877
+ {showShareLinks && shareUrlPlacement === "bottom" ? (
878
+ // The tabbed layout reorders its sections with `order-*`, so links
879
+ // placed at the bottom need an order of their own to stay last.
880
+ <div className={props.agentTabContent ? "order-3" : undefined}>
881
+ {shareLinks}
882
+ </div>
883
+ ) : null}
878
884
 
879
885
  {props.shareFooterContent}
880
886
  </div>
@@ -1,23 +1,23 @@
1
1
  :root {
2
- --resource-icon-gray: #787774;
3
- --resource-icon-brown: #9f6b53;
4
- --resource-icon-orange: #c76c24;
5
- --resource-icon-yellow: #a78317;
6
- --resource-icon-green: #448361;
7
- --resource-icon-blue: #337ea9;
8
- --resource-icon-purple: #9065b0;
9
- --resource-icon-pink: #b64c7d;
10
- --resource-icon-red: #c4554d;
2
+ --resource-icon-gray: #525252;
3
+ --resource-icon-brown: #905a33;
4
+ --resource-icon-orange: #ca3500;
5
+ --resource-icon-yellow: #a65f00;
6
+ --resource-icon-green: #008236;
7
+ --resource-icon-blue: #1447e6;
8
+ --resource-icon-purple: #8200db;
9
+ --resource-icon-pink: #c6005c;
10
+ --resource-icon-red: #c10007;
11
11
  }
12
12
 
13
13
  .dark {
14
- --resource-icon-gray: #a6a6a3;
15
- --resource-icon-brown: #c19a80;
16
- --resource-icon-orange: #e6a168;
17
- --resource-icon-yellow: #d4bc6a;
18
- --resource-icon-green: #83bd9d;
19
- --resource-icon-blue: #78b5d9;
20
- --resource-icon-purple: #b89ed2;
21
- --resource-icon-pink: #dc96b6;
22
- --resource-icon-red: #e5948d;
14
+ --resource-icon-gray: #a1a1a1;
15
+ --resource-icon-brown: #e0b491;
16
+ --resource-icon-orange: #ffb86a;
17
+ --resource-icon-yellow: #ffdf20;
18
+ --resource-icon-green: #7bf1a8;
19
+ --resource-icon-blue: #8ec5ff;
20
+ --resource-icon-purple: #dab2ff;
21
+ --resource-icon-pink: #fda5d5;
22
+ --resource-icon-red: #ffa2a2;
23
23
  }