@codingame/monaco-vscode-welcome-service-override 36.2.7 → 37.2.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 (35) hide show
  1. package/index.js +1 -0
  2. package/package.json +3 -2
  3. package/vscode/src/vs/workbench/contrib/onboarding/browser/media/spotlight.css +5 -0
  4. package/vscode/src/vs/workbench/contrib/onboarding/browser/onboarding.contribution.js +37 -7
  5. package/vscode/src/vs/workbench/contrib/onboarding/browser/onboardingService.d.ts +2 -0
  6. package/vscode/src/vs/workbench/contrib/onboarding/browser/onboardingService.js +36 -5
  7. package/vscode/src/vs/workbench/contrib/onboarding/browser/sequence/runOnboardingStep.d.ts +17 -0
  8. package/vscode/src/vs/workbench/contrib/onboarding/browser/sequence/runOnboardingStep.js +32 -0
  9. package/vscode/src/vs/workbench/contrib/onboarding/browser/sequence/sequencePresentation.d.ts +10 -0
  10. package/vscode/src/vs/workbench/contrib/onboarding/browser/sequence/sequencePresentation.js +154 -0
  11. package/vscode/src/vs/workbench/contrib/onboarding/browser/spotlight/onboardingTarget.d.ts +7 -1
  12. package/vscode/src/vs/workbench/contrib/onboarding/browser/spotlight/onboardingTarget.js +5 -1
  13. package/vscode/src/vs/workbench/contrib/onboarding/browser/spotlight/spotlightOverlay.d.ts +13 -9
  14. package/vscode/src/vs/workbench/contrib/onboarding/browser/spotlight/spotlightOverlay.js +60 -15
  15. package/vscode/src/vs/workbench/contrib/onboarding/browser/spotlight/spotlightPresentation.d.ts +5 -1
  16. package/vscode/src/vs/workbench/contrib/onboarding/browser/spotlight/spotlightPresentation.js +222 -49
  17. package/vscode/src/vs/workbench/contrib/onboarding/browser/spotlight/spotlightTypes.d.ts +23 -5
  18. package/vscode/src/vs/workbench/contrib/onboarding/common/onboardingPresentation.d.ts +4 -0
  19. package/vscode/src/vs/workbench/contrib/onboarding/common/onboardingScenario.d.ts +9 -8
  20. package/vscode/src/vs/workbench/contrib/onboarding/common/onboardingScenarioService.d.ts +7 -0
  21. package/vscode/src/vs/workbench/contrib/onboarding/common/onboardingScenarioService.js +2 -1
  22. package/vscode/src/vs/workbench/contrib/onboarding/common/onboardingSequence.d.ts +45 -0
  23. package/vscode/src/vs/workbench/contrib/onboarding/common/onboardingSequence.js +29 -0
  24. package/vscode/src/vs/workbench/contrib/welcomeAgentSessions/browser/agentSessionsWelcome.contribution.d.ts +1 -0
  25. package/vscode/src/vs/workbench/contrib/welcomeAgentSessions/browser/agentSessionsWelcome.contribution.js +158 -0
  26. package/vscode/src/vs/workbench/contrib/welcomeAgentSessions/browser/agentSessionsWelcome.d.ts +105 -0
  27. package/vscode/src/vs/workbench/contrib/welcomeAgentSessions/browser/agentSessionsWelcome.js +765 -0
  28. package/vscode/src/vs/workbench/contrib/welcomeAgentSessions/browser/media/agentSessionsWelcome.css +564 -0
  29. package/vscode/src/vs/workbench/contrib/welcomeOnboarding/browser/media/variationA.css +2 -149
  30. package/vscode/src/vs/workbench/contrib/welcomeOnboarding/browser/onboardingVariationA.d.ts +5 -5
  31. package/vscode/src/vs/workbench/contrib/welcomeOnboarding/browser/onboardingVariationA.js +61 -131
  32. package/vscode/src/vs/workbench/contrib/welcomeOnboarding/browser/welcomeOnboarding.contribution.js +1 -1
  33. package/vscode/src/vs/workbench/contrib/welcomeViews/common/newFile.contribution.js +10 -10
  34. package/vscode/src/vs/workbench/contrib/welcomeViews/common/viewsWelcomeContribution.js +2 -2
  35. package/vscode/src/vs/workbench/contrib/welcomeViews/common/viewsWelcomeExtensionPoint.js +8 -8
package/index.js CHANGED
@@ -8,6 +8,7 @@ import './vscode/src/vs/workbench/contrib/onboarding/browser/onboarding.contribu
8
8
  import './vscode/src/vs/workbench/contrib/welcomeViews/common/viewsWelcome.contribution.js';
9
9
  import './vscode/src/vs/workbench/contrib/welcomeViews/common/newFile.contribution.js';
10
10
  import './vscode/src/vs/workbench/contrib/welcomeOnboarding/browser/welcomeOnboarding.contribution.js';
11
+ import './vscode/src/vs/workbench/contrib/welcomeAgentSessions/browser/agentSessionsWelcome.contribution.js';
11
12
 
12
13
  function getServiceOverride() {
13
14
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codingame/monaco-vscode-welcome-service-override",
3
- "version": "36.2.7",
3
+ "version": "37.2.0",
4
4
  "private": false,
5
5
  "description": "VSCode public API plugged on the monaco editor - welcome service-override",
6
6
  "keywords": [],
@@ -15,7 +15,8 @@
15
15
  },
16
16
  "type": "module",
17
17
  "dependencies": {
18
- "@codingame/monaco-vscode-api": "36.2.7"
18
+ "@codingame/monaco-vscode-api": "37.2.0",
19
+ "@codingame/monaco-vscode-katex-common": "37.2.0"
19
20
  },
20
21
  "main": "index.js",
21
22
  "module": "index.js",
@@ -13,6 +13,11 @@
13
13
  z-index: 2600;
14
14
  }
15
15
 
16
+ /* Expanded pickers and mobile sheets remain above the spotlight blocker. */
17
+ .spotlight-overlay.target-overlay-visible {
18
+ z-index: 1999;
19
+ }
20
+
16
21
  /* Full-screen click blocker. Transparent; swallows interaction outside the hole. */
17
22
  .spotlight-blocker {
18
23
  position: fixed;
@@ -12,21 +12,34 @@ import { workbenchConfigurationNodeBase } from '@codingame/monaco-vscode-api/vsc
12
12
  import { registerWorkbenchContribution2, WorkbenchPhase } from '@codingame/monaco-vscode-api/vscode/vs/workbench/common/contributions';
13
13
  import { onboardingPresentationRegistry } from '../common/onboardingPresentation.js';
14
14
  import { onboardingScenarioRegistry } from '../common/onboardingRegistry.js';
15
- import { ONBOARDING_DEVELOPER_MODE_CONFIG, ONBOARDING_ENABLED_CONFIG } from '../common/onboardingScenarioService.js';
15
+ import { onboardingSequenceStepPresentationRegistry } from '../common/onboardingSequence.js';
16
+ import { ONBOARDING_DEVELOPER_MODE_VARIATIONS_CONFIG, ONBOARDING_DEVELOPER_MODE_CONFIG, ONBOARDING_ENABLED_CONFIG } from '../common/onboardingScenarioService.js';
16
17
  import { IOnboardingScenarioService } from '@codingame/monaco-vscode-api/vscode/vs/workbench/contrib/onboarding/common/onboardingScenarioService.service';
17
18
  import './onboardingService.js';
19
+ import { RunOnboardingStepPresentation } from './sequence/runOnboardingStep.js';
20
+ import { OnboardingSequencePresentation } from './sequence/sequencePresentation.js';
18
21
  import { SpotlightPresentation } from './spotlight/spotlightPresentation.js';
19
22
 
20
23
  const configurationRegistry = ( Registry.as(Extensions.Configuration));
21
24
  function buildDeveloperModeConfigurationNode() {
22
25
  const properties = {};
23
26
  const defaultValue = {};
24
- for (const id of ( onboardingScenarioRegistry.getScenarios().map(scenario => scenario.id)).sort()) {
25
- properties[id] = {
27
+ const variationProperties = {};
28
+ const variationDefaultValue = {};
29
+ for (const scenario of [...onboardingScenarioRegistry.getScenarios()].sort((a, b) => a.id.localeCompare(b.id))) {
30
+ properties[scenario.id] = {
26
31
  type: "boolean",
27
32
  default: false
28
33
  };
29
- defaultValue[id] = false;
34
+ defaultValue[scenario.id] = false;
35
+ if (scenario.developerModeVariations?.length) {
36
+ variationProperties[scenario.id] = {
37
+ type: "string",
38
+ default: "",
39
+ enum: ["", ...scenario.developerModeVariations]
40
+ };
41
+ variationDefaultValue[scenario.id] = "";
42
+ }
30
43
  }
31
44
  return {
32
45
  ...workbenchConfigurationNodeBase,
@@ -40,10 +53,23 @@ function buildDeveloperModeConfigurationNode() {
40
53
  },
41
54
  tags: ["experimental"],
42
55
  description: ( localize(
43
- 12885,
56
+ 14868,
44
57
  "Map of onboarding scenario/tour id to whether developer mode is enabled for it. When enabled for a scenario, that onboarding tour ignores usage-based eligibility checks (such as how many sessions you have started), previously persisted shown state, and any linked experiment (so it is shown even if the experiment is not running or you are in the control group). It does not override the {0} setting. The tour is still shown at most once per window session, so reload the window to show it again.",
45
58
  `\`#${ONBOARDING_ENABLED_CONFIG}#\``
46
59
  ))
60
+ },
61
+ [ONBOARDING_DEVELOPER_MODE_VARIATIONS_CONFIG]: {
62
+ type: "object",
63
+ default: variationDefaultValue,
64
+ properties: variationProperties,
65
+ additionalProperties: {
66
+ type: "string"
67
+ },
68
+ tags: ["experimental"],
69
+ description: ( localize(
70
+ 14869,
71
+ "Map of onboarding scenario/tour id to the variation used while developer mode is enabled for that scenario. An empty value uses the experiment-selected or default variation."
72
+ ))
47
73
  }
48
74
  }
49
75
  };
@@ -56,7 +82,7 @@ configurationRegistry.registerConfiguration({
56
82
  type: "boolean",
57
83
  default: true,
58
84
  description: ( localize(
59
- 12886,
85
+ 14870,
60
86
  "When enabled, onboarding tours and hints may appear automatically to highlight features. Disabling this does not affect tours you start manually."
61
87
  ))
62
88
  }
@@ -83,6 +109,10 @@ let OnboardingContribution = class OnboardingContribution extends Disposable {
83
109
  );
84
110
  const spotlight = this._register(instantiationService.createInstance(SpotlightPresentation));
85
111
  this._register(onboardingPresentationRegistry.register(spotlight));
112
+ this._register(onboardingSequenceStepPresentationRegistry.register(spotlight));
113
+ const sequence = this._register(( new OnboardingSequencePresentation()));
114
+ this._register(onboardingPresentationRegistry.register(sequence));
115
+ this._register(onboardingSequenceStepPresentationRegistry.register(( new RunOnboardingStepPresentation())));
86
116
  onboardingService.start();
87
117
  }
88
118
  };
@@ -96,7 +126,7 @@ registerAction2(class extends Action2 {
96
126
  constructor() {
97
127
  super({
98
128
  id: "workbench.action.onboarding.resetShownState",
99
- title: ( localize2(12887, "Reset Onboarding Shown State")),
129
+ title: ( localize2(14871, "Reset Onboarding Shown State")),
100
130
  category: Categories.Developer,
101
131
  f1: true
102
132
  });
@@ -93,6 +93,8 @@ export declare class OnboardingScenarioService extends Disposable implements IOn
93
93
  private _pump;
94
94
  private _doPump;
95
95
  private _runPresentation;
96
+ /** Emit an impression when a presentation has rendered visible onboarding UI. */
97
+ private _reportShown;
96
98
  /** Emit per-tour telemetry. Only called when a tour was actually shown. */
97
99
  private _reportOutcome;
98
100
  private _registerTriggerListeners;
@@ -61,7 +61,10 @@ let OnboardingScenarioService = class OnboardingScenarioService extends Disposab
61
61
  this._openedAssignmentContextIds = this._loadOpenedIds();
62
62
  this.assignmentService.addTelemetryAssignmentFilter({
63
63
  id: "onboarding",
64
- exclude: assignment => assignment.startsWith(ONBOARDING_ASSIGNMENT_CONTEXT_PREFIX) && !( this._openedAssignmentContextIds.has(assignment)),
64
+ exclude: assignment => {
65
+ const variant = getAssignmentContextVariant(assignment);
66
+ return variant.startsWith(ONBOARDING_ASSIGNMENT_CONTEXT_PREFIX) && !( this._openedAssignmentContextIds.has(variant));
67
+ },
65
68
  onDidChange: this._onDidChangeOpenedIds.event
66
69
  });
67
70
  this._register(this.lifecycleService.onWillShutdown(() => this._stop()));
@@ -136,10 +139,19 @@ let OnboardingScenarioService = class OnboardingScenarioService extends Disposab
136
139
  claimedSeenKeys.add(this._seenKey(scenario));
137
140
  }
138
141
  }
139
- for (const scenario of onboardingScenarioRegistry.getScenarios()) {
140
- if (!this._isAutoEligible(scenario)) {
141
- continue;
142
+ const eligibleScenarios = ( onboardingScenarioRegistry.getScenarios().map((scenario, registrationIndex) => ({
143
+ scenario,
144
+ registrationIndex
145
+ }))).filter((
146
+ {
147
+ scenario
142
148
  }
149
+ ) => this._isAutoEligible(scenario)).sort(
150
+ (a, b) => (b.scenario.priority ?? 0) - (a.scenario.priority ?? 0) || a.registrationIndex - b.registrationIndex
151
+ );
152
+ for (const {
153
+ scenario
154
+ } of eligibleScenarios) {
143
155
  const seenKey = this._seenKey(scenario);
144
156
  if (!scenario.repeatable && ( claimedSeenKeys.has(seenKey))) {
145
157
  continue;
@@ -242,10 +254,17 @@ let OnboardingScenarioService = class OnboardingScenarioService extends Disposab
242
254
  const abort = ( new Emitter());
243
255
  this._activeAbort = abort;
244
256
  const startTime = Date.now();
257
+ let didReportShown = false;
245
258
  try {
246
259
  const result = await presentation.run(scenario, {
247
260
  targetWindow: mainWindow,
248
- onAbort: abort.event
261
+ onAbort: abort.event,
262
+ onDidShow: () => {
263
+ if (!didReportShown) {
264
+ didReportShown = true;
265
+ this._reportShown(scenario);
266
+ }
267
+ }
249
268
  });
250
269
  this._recordOutcome(this._seenKey(scenario), result.outcome);
251
270
  if (result.shown) {
@@ -257,6 +276,14 @@ let OnboardingScenarioService = class OnboardingScenarioService extends Disposab
257
276
  abort.dispose();
258
277
  }
259
278
  }
279
+ _reportShown(scenario) {
280
+ const experimentState = scenario.experiment ? this._experimentStates.get(scenario.id) : undefined;
281
+ this.telemetryService.publicLog2("onboarding.scenarioShown", {
282
+ scenarioId: scenario.id,
283
+ experimentActive: experimentState?.active === true,
284
+ experimentAssignmentContextId: experimentState?.active ? experimentState.assignmentContextId : undefined
285
+ });
286
+ }
260
287
  _reportOutcome(scenario, result, durationMs) {
261
288
  const experimentActive = !!scenario.experiment && this._experimentStates.get(scenario.id)?.active === true;
262
289
  this.telemetryService.publicLog2("onboarding.scenarioOutcome", {
@@ -374,5 +401,9 @@ let OnboardingScenarioService = class OnboardingScenarioService extends Disposab
374
401
  }
375
402
  };
376
403
  OnboardingScenarioService = OnboardingScenarioService_1 = ( __decorate([( __param(0, IStorageService)), ( __param(1, IContextKeyService)), ( __param(2, IConfigurationService)), ( __param(3, ILifecycleService)), ( __param(4, IWorkbenchAssignmentService)), ( __param(5, ITelemetryService))], OnboardingScenarioService));
404
+ function getAssignmentContextVariant(assignment) {
405
+ const separatorIndex = assignment.lastIndexOf(":");
406
+ return separatorIndex === -1 ? assignment : assignment.slice(0, separatorIndex);
407
+ }
377
408
 
378
409
  export { OnboardingScenarioService };
@@ -0,0 +1,17 @@
1
+ import { CancellationToken } from "@codingame/monaco-vscode-api/vscode/vs/base/common/cancellation";
2
+ import { IOnboardingSequenceStep, IOnboardingSequenceStepContext, IOnboardingSequenceStepPresentation, IOnboardingSequenceStepResult } from "../../common/onboardingSequence.js";
3
+ export declare const RUN_ONBOARDING_STEP_KIND = "run";
4
+ export interface IRunOnboardingStepResult {
5
+ readonly shown?: boolean;
6
+ }
7
+ /** Callback payload for a cancellable non-visual sequence step. */
8
+ export interface IRunOnboardingStepPayload {
9
+ readonly run: (token: CancellationToken) => Promise<IRunOnboardingStepResult | void> | IRunOnboardingStepResult | void;
10
+ }
11
+ /** Executes a run-step callback once and continues after reported errors. */
12
+ export declare class RunOnboardingStepPresentation implements IOnboardingSequenceStepPresentation {
13
+ readonly kind = "run";
14
+ readonly countsAsVisualStep = false;
15
+ readonly runOnce = true;
16
+ runStep(step: IOnboardingSequenceStep, context: IOnboardingSequenceStepContext): Promise<IOnboardingSequenceStepResult>;
17
+ }
@@ -0,0 +1,32 @@
1
+
2
+ import { raceCancellation } from '@codingame/monaco-vscode-api/vscode/vs/base/common/async';
3
+ import { onUnexpectedError } from '@codingame/monaco-vscode-api/vscode/vs/base/common/errors';
4
+
5
+ const RUN_ONBOARDING_STEP_KIND = 'run';
6
+ class RunOnboardingStepPresentation {
7
+ constructor() {
8
+ this.kind = RUN_ONBOARDING_STEP_KIND;
9
+ this.countsAsVisualStep = false;
10
+ this.runOnce = true;
11
+ }
12
+ async runStep(step, context) {
13
+ if (context.cancellationToken.isCancellationRequested) {
14
+ return { action: 'abort', shown: false };
15
+ }
16
+ let result = undefined;
17
+ try {
18
+ const payload = step.payload;
19
+ result = await raceCancellation(Promise.resolve(payload.run(context.cancellationToken)), context.cancellationToken);
20
+ }
21
+ catch (error) {
22
+ if (!context.cancellationToken.isCancellationRequested) {
23
+ onUnexpectedError(error);
24
+ }
25
+ }
26
+ return context.cancellationToken.isCancellationRequested
27
+ ? { action: 'abort', shown: false }
28
+ : { action: 'next', shown: result?.shown === true };
29
+ }
30
+ }
31
+
32
+ export { RUN_ONBOARDING_STEP_KIND, RunOnboardingStepPresentation };
@@ -0,0 +1,10 @@
1
+ import { Disposable } from "@codingame/monaco-vscode-api/vscode/vs/base/common/lifecycle";
2
+ import { IOnboardingPresentation, IOnboardingRunContext } from "../../common/onboardingPresentation.js";
3
+ import { IOnboardingRunResult, IOnboardingScenario } from "../../common/onboardingScenario.js";
4
+ /** Runs a heterogeneous sequence while leaving each step's rendering to its registered kind. */
5
+ export declare class OnboardingSequencePresentation extends Disposable implements IOnboardingPresentation {
6
+ readonly kind = "sequence";
7
+ run(scenario: IOnboardingScenario, context: IOnboardingRunContext): Promise<IOnboardingRunResult>;
8
+ private _presentation;
9
+ private _visualStepIndex;
10
+ }
@@ -0,0 +1,154 @@
1
+
2
+ import { CancellationTokenSource } from '@codingame/monaco-vscode-api/vscode/vs/base/common/cancellation';
3
+ import { onUnexpectedError } from '@codingame/monaco-vscode-api/vscode/vs/base/common/errors';
4
+ import { Disposable, DisposableStore } from '@codingame/monaco-vscode-api/vscode/vs/base/common/lifecycle';
5
+ import { OnboardingDismissReason, OnboardingOutcome } from '../../common/onboardingScenario.js';
6
+ import { ONBOARDING_SEQUENCE_PRESENTATION_KIND, onboardingSequenceStepPresentationRegistry } from '../../common/onboardingSequence.js';
7
+
8
+ class OnboardingSequencePresentation extends Disposable {
9
+ constructor() {
10
+ super(...arguments);
11
+ this.kind = ONBOARDING_SEQUENCE_PRESENTATION_KIND;
12
+ }
13
+ async run(scenario, context) {
14
+ const steps = scenario.presentation.payload?.steps ?? [];
15
+ if (steps.length === 0) {
16
+ return {
17
+ outcome: OnboardingOutcome.Completed,
18
+ shown: false,
19
+ dismissReason: OnboardingDismissReason.Completed,
20
+ lastStepIndex: 0,
21
+ stepCount: 0
22
+ };
23
+ }
24
+ const store = ( new DisposableStore());
25
+ try {
26
+ const cancellation = store.add(( new CancellationTokenSource()));
27
+ store.add(context.onAbort(() => cancellation.cancel()));
28
+ const skippedVisualSteps = ( new Set());
29
+ const shownVisualSteps = ( new Set());
30
+ const executedRunOnceSteps = ( new Set());
31
+ const visualStepCount = steps.reduce(
32
+ (count, step) => count + (this._presentation(step)?.countsAsVisualStep ? 1 : 0),
33
+ 0
34
+ );
35
+ let index = 0;
36
+ let direction = 1;
37
+ let shown = false;
38
+ let lastStepIndex = 0;
39
+ let dismissReason = OnboardingDismissReason.Completed;
40
+ while (index >= 0 && index < steps.length && !cancellation.token.isCancellationRequested) {
41
+ const step = steps[index];
42
+ const presentation = this._presentation(step);
43
+ if (!presentation) {
44
+ onUnexpectedError(( new Error(`No onboarding sequence step presentation registered for '${step.kind}'.`)));
45
+ return {
46
+ outcome: OnboardingOutcome.Aborted,
47
+ shown,
48
+ dismissReason: OnboardingDismissReason.Aborted,
49
+ lastStepIndex,
50
+ stepCount: steps.length
51
+ };
52
+ }
53
+ if (!presentation.countsAsVisualStep && direction === -1) {
54
+ index--;
55
+ continue;
56
+ }
57
+ if (presentation.runOnce && ( executedRunOnceSteps.has(index))) {
58
+ index += direction;
59
+ continue;
60
+ }
61
+ if (presentation.runOnce) {
62
+ executedRunOnceSteps.add(index);
63
+ }
64
+ if (presentation.countsAsVisualStep) {
65
+ skippedVisualSteps.delete(index);
66
+ }
67
+ const visualStepIndex = this._visualStepIndex(steps, index, skippedVisualSteps);
68
+ const currentVisualStepCount = visualStepCount - skippedVisualSteps.size;
69
+ if (!presentation.countsAsVisualStep) {
70
+ lastStepIndex = Math.max(lastStepIndex, index);
71
+ }
72
+ const result = await presentation.runStep(step, {
73
+ ...context,
74
+ cancellationToken: cancellation.token,
75
+ stepIndex: index,
76
+ visualStepIndex,
77
+ visualStepCount: currentVisualStepCount,
78
+ canGoBack: ( Array.from(shownVisualSteps).some(stepIndex => stepIndex < index)),
79
+ isLastVisualStep: visualStepIndex === currentVisualStepCount - 1
80
+ });
81
+ if (cancellation.token.isCancellationRequested || result.action === "abort") {
82
+ return {
83
+ outcome: OnboardingOutcome.Aborted,
84
+ shown,
85
+ dismissReason: OnboardingDismissReason.Aborted,
86
+ lastStepIndex,
87
+ stepCount: steps.length
88
+ };
89
+ }
90
+ if (result.shown) {
91
+ shown = true;
92
+ lastStepIndex = Math.max(lastStepIndex, index);
93
+ if (presentation.countsAsVisualStep) {
94
+ shownVisualSteps.add(index);
95
+ }
96
+ }
97
+ switch (result.action) {
98
+ case "next":
99
+ dismissReason = result.dismissReason ?? dismissReason;
100
+ direction = 1;
101
+ index++;
102
+ break;
103
+ case "back":
104
+ direction = -1;
105
+ index--;
106
+ break;
107
+ case "skipStep":
108
+ if (presentation.countsAsVisualStep) {
109
+ skippedVisualSteps.add(index);
110
+ }
111
+ index += direction;
112
+ break;
113
+ case "skipSequence":
114
+ return {
115
+ outcome: OnboardingOutcome.Skipped,
116
+ shown,
117
+ dismissReason: result.dismissReason ?? OnboardingDismissReason.SkipButton,
118
+ lastStepIndex,
119
+ stepCount: steps.length
120
+ };
121
+ }
122
+ }
123
+ return cancellation.token.isCancellationRequested ? {
124
+ outcome: OnboardingOutcome.Aborted,
125
+ shown,
126
+ dismissReason: OnboardingDismissReason.Aborted,
127
+ lastStepIndex,
128
+ stepCount: steps.length
129
+ } : {
130
+ outcome: OnboardingOutcome.Completed,
131
+ shown,
132
+ dismissReason,
133
+ lastStepIndex,
134
+ stepCount: steps.length
135
+ };
136
+ } finally {
137
+ store.dispose();
138
+ }
139
+ }
140
+ _presentation(step) {
141
+ return onboardingSequenceStepPresentationRegistry.get(step.kind);
142
+ }
143
+ _visualStepIndex(steps, index, skippedVisualSteps) {
144
+ let visualStepIndex = 0;
145
+ for (let stepIndex = 0; stepIndex < index; stepIndex++) {
146
+ if (this._presentation(steps[stepIndex])?.countsAsVisualStep && !( skippedVisualSteps.has(stepIndex))) {
147
+ visualStepIndex++;
148
+ }
149
+ }
150
+ return visualStepIndex;
151
+ }
152
+ }
153
+
154
+ export { OnboardingSequencePresentation };
@@ -8,12 +8,18 @@ import { IDisposable } from "@codingame/monaco-vscode-api/vscode/vs/base/common/
8
8
  */
9
9
  export declare const ONBOARDING_TARGET_ATTR = "data-onboarding-id";
10
10
  export declare const ONBOARDING_TARGET_PULSE_CLASS = "onboarding-target-pulse";
11
+ export interface IOnboardingTargetOptions {
12
+ /** Opens or expands the target before its spotlight step is shown. */
13
+ readonly open?: () => Promise<void> | void;
14
+ }
11
15
  /**
12
16
  * Marks `element` as the onboarding target identified by `id`.
13
17
  *
14
18
  * @returns A disposable that removes the attribute again.
15
19
  */
16
- export declare function markOnboardingTarget(element: HTMLElement, id: string): IDisposable;
20
+ export declare function markOnboardingTarget(element: HTMLElement, id: string, options?: IOnboardingTargetOptions): IDisposable;
21
+ /** Opens or expands a target through the behavior registered by its owner. */
22
+ export declare function openOnboardingTarget(element: HTMLElement): Promise<void> | void;
17
23
  /**
18
24
  * Applies the standard onboarding pulse treatment to `element`.
19
25
  *
@@ -5,6 +5,10 @@ import * as onboardingTarget from '../media/onboardingTarget.css';
5
5
 
6
6
  registerCss(onboardingTarget);
7
7
  const ONBOARDING_TARGET_ATTR = "data-onboarding-id";
8
+ const onboardingTargetRegistrations = ( new WeakMap());
9
+ function openOnboardingTarget(element) {
10
+ return onboardingTargetRegistrations.get(element)?.options.open?.();
11
+ }
8
12
  function findOnboardingTarget(targetWindow, id) {
9
13
  const selector = `[${ONBOARDING_TARGET_ATTR}="${CSS.escape(id)}"]`;
10
14
  const targets = Array.from(targetWindow.document.querySelectorAll(selector));
@@ -22,4 +26,4 @@ function isVisibleOnboardingTarget(targetWindow, target) {
22
26
  return rect.width > 0 && rect.height > 0;
23
27
  }
24
28
 
25
- export { ONBOARDING_TARGET_ATTR, findOnboardingTarget };
29
+ export { ONBOARDING_TARGET_ATTR, findOnboardingTarget, openOnboardingTarget };
@@ -1,7 +1,7 @@
1
1
  import { Disposable } from "@codingame/monaco-vscode-api/vscode/vs/base/common/lifecycle";
2
2
  import { Event } from "@codingame/monaco-vscode-api/vscode/vs/base/common/event";
3
3
  import { IMarkdownString } from "@codingame/monaco-vscode-api/vscode/vs/base/common/htmlContent";
4
- import { SpotlightPlacement } from "./spotlightTypes.js";
4
+ import { SpotlightPlacement, SpotlightTargetClickBehavior } from "./spotlightTypes.js";
5
5
  import { OnboardingDismissReason } from "../../common/onboardingScenario.js";
6
6
  /** How the user advanced to the next step. */
7
7
  export type SpotlightAdvanceSource = "button" | "target";
@@ -11,9 +11,11 @@ export type SpotlightSkipReason = OnboardingDismissReason.SkipButton | Onboardin
11
11
  export interface ISpotlightContent {
12
12
  readonly title: string;
13
13
  readonly description: string | IMarkdownString;
14
+ /** Localized primary button label, replacing the default Next or Done. */
15
+ readonly nextButtonLabel?: string;
14
16
  /** Zero-based index of the current step. */
15
17
  readonly stepIndex: number;
16
- /** Total number of steps in the tour. */
18
+ /** Total number of steps in the tour. Progress is displayed only for multi-step tours. */
17
19
  readonly stepCount: number;
18
20
  /** Whether a "Back" action should be offered. */
19
21
  readonly canGoBack: boolean;
@@ -25,12 +27,10 @@ export interface ISpotlightShowOptions {
25
27
  readonly placement?: SpotlightPlacement;
26
28
  readonly allowTargetInteraction?: boolean;
27
29
  readonly padding?: number;
28
- /**
29
- * When set, the step advances (fires `onDidClickNext`) when the user clicks
30
- * the spotlighted target itself. The "Next" button is hidden and the target
31
- * is kept interactive so the user can press it to continue.
32
- */
33
- readonly advanceOnTargetClick?: boolean;
30
+ readonly hideNext?: boolean;
31
+ readonly targetOverlayVisible?: boolean;
32
+ /** Advances on target activation; `advanceOnly` consumes the activation without running its action. */
33
+ readonly advanceOnTargetClick?: SpotlightTargetClickBehavior;
34
34
  }
35
35
  /**
36
36
  * A pure-DOM spotlight overlay: dims the window, cuts a highlight hole around a
@@ -63,11 +63,14 @@ export declare class SpotlightOverlay extends Disposable {
63
63
  readonly onDidSkip: Event<SpotlightSkipReason>;
64
64
  private _target;
65
65
  private _options;
66
+ private _hasShown;
66
67
  private _previousFocus;
67
68
  private _scheduledLayout;
68
69
  constructor(_container: HTMLElement, _resizeObserverCtor?: typeof ResizeObserver);
69
70
  /** Show `content` spotlighting `target`. */
70
71
  show(target: HTMLElement, content: ISpotlightContent, options?: ISpotlightShowOptions): void;
72
+ /** Hide the current step while another target is being resolved. */
73
+ hide(): void;
71
74
  /** Recompute the hole and callout positions for the current target. */
72
75
  layout(): void;
73
76
  private _layoutBlocker;
@@ -83,13 +86,14 @@ export declare class SpotlightOverlay extends Disposable {
83
86
  private _trapFocus;
84
87
  /**
85
88
  * The focusable elements participating in the focus trap, in DOM order: the
86
- * spotlighted target (when the step advances by pressing it), then any
89
+ * spotlighted target (when it is interactive or the Next button is hidden), then any
87
90
  * interactive content in the (possibly markdown) description, then the visible
88
91
  * action buttons. Including the target keeps the spotlighted control
89
92
  * keyboard-reachable, and querying the description keeps markdown links
90
93
  * reachable despite `aria-modal`.
91
94
  */
92
95
  private _collectFocusable;
96
+ private _isTabbable;
93
97
  scheduleLayout(): void;
94
98
  private _restoreFocus;
95
99
  dispose(): void;