doe-sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +509 -0
- package/dist/cli/index.d.ts +17 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +118 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init.d.ts +25 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +100 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/login.d.ts +52 -0
- package/dist/cli/login.d.ts.map +1 -0
- package/dist/cli/login.js +571 -0
- package/dist/cli/login.js.map +1 -0
- package/dist/cli/publish.d.ts +27 -0
- package/dist/cli/publish.d.ts.map +1 -0
- package/dist/cli/publish.js +531 -0
- package/dist/cli/publish.js.map +1 -0
- package/dist/cli/scaffold.d.ts +18 -0
- package/dist/cli/scaffold.d.ts.map +1 -0
- package/dist/cli/scaffold.js +252 -0
- package/dist/cli/scaffold.js.map +1 -0
- package/dist/cli/ui.d.ts +57 -0
- package/dist/cli/ui.d.ts.map +1 -0
- package/dist/cli/ui.js +339 -0
- package/dist/cli/ui.js.map +1 -0
- package/dist/cli/validate.d.ts +28 -0
- package/dist/cli/validate.d.ts.map +1 -0
- package/dist/cli/validate.js +1270 -0
- package/dist/cli/validate.js.map +1 -0
- package/dist/compat/legacy-adapter.d.ts +198 -0
- package/dist/compat/legacy-adapter.d.ts.map +1 -0
- package/dist/compat/legacy-adapter.js +318 -0
- package/dist/compat/legacy-adapter.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/runtime/client.d.ts +370 -0
- package/dist/runtime/client.d.ts.map +1 -0
- package/dist/runtime/client.js +470 -0
- package/dist/runtime/client.js.map +1 -0
- package/dist/runtime/index.d.ts +8 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +7 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/types/api.d.ts +564 -0
- package/dist/types/api.d.ts.map +1 -0
- package/dist/types/api.js +11 -0
- package/dist/types/api.js.map +1 -0
- package/dist/types/index.d.ts +12 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +10 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/manifest.d.ts +412 -0
- package/dist/types/manifest.d.ts.map +1 -0
- package/dist/types/manifest.js +42 -0
- package/dist/types/manifest.js.map +1 -0
- package/dist/types/marketplace-categories.d.ts +9 -0
- package/dist/types/marketplace-categories.d.ts.map +1 -0
- package/dist/types/marketplace-categories.js +16 -0
- package/dist/types/marketplace-categories.js.map +1 -0
- package/dist/types/permissions.d.ts +86 -0
- package/dist/types/permissions.d.ts.map +1 -0
- package/dist/types/permissions.js +295 -0
- package/dist/types/permissions.js.map +1 -0
- package/dist/types/theme/index.d.ts +7 -0
- package/dist/types/theme/index.d.ts.map +1 -0
- package/dist/types/theme/index.js +7 -0
- package/dist/types/theme/index.js.map +1 -0
- package/dist/types/theme/schema.d.ts +1205 -0
- package/dist/types/theme/schema.d.ts.map +1 -0
- package/dist/types/theme/schema.js +325 -0
- package/dist/types/theme/schema.js.map +1 -0
- package/dist/types/theme/types.d.ts +648 -0
- package/dist/types/theme/types.d.ts.map +1 -0
- package/dist/types/theme/types.js +8 -0
- package/dist/types/theme/types.js.map +1 -0
- package/package.json +75 -0
- package/templates/extension/README.md +254 -0
- package/templates/extension/icon.png +0 -0
- package/templates/extension/index.html +42 -0
- package/templates/extension/manifest.json +57 -0
- package/templates/extension/package.json +24 -0
- package/templates/extension/src/App.tsx +252 -0
- package/templates/extension/src/components/OnboardingComplete.tsx +190 -0
- package/templates/extension/src/components/OnboardingProgress.tsx +82 -0
- package/templates/extension/src/components/OnboardingWelcome.tsx +166 -0
- package/templates/extension/src/components/StepContainer.tsx +217 -0
- package/templates/extension/src/components/playground/CanvasTab.tsx +24 -0
- package/templates/extension/src/components/playground/ConfigTab.tsx +24 -0
- package/templates/extension/src/components/playground/EventsTab.tsx +24 -0
- package/templates/extension/src/components/playground/InfoTab.tsx +89 -0
- package/templates/extension/src/components/playground/NetworkTab.tsx +24 -0
- package/templates/extension/src/components/playground/PlaygroundContainer.tsx +184 -0
- package/templates/extension/src/components/playground/ResultDisplay.tsx +30 -0
- package/templates/extension/src/components/playground/StorageTab.tsx +24 -0
- package/templates/extension/src/components/playground/UITab.tsx +24 -0
- package/templates/extension/src/components/shared/CanvasControls.tsx +130 -0
- package/templates/extension/src/components/shared/ConfigControls.tsx +154 -0
- package/templates/extension/src/components/shared/EventsControls.tsx +232 -0
- package/templates/extension/src/components/shared/InfoControls.tsx +281 -0
- package/templates/extension/src/components/shared/NetworkControls.tsx +328 -0
- package/templates/extension/src/components/shared/StorageControls.tsx +203 -0
- package/templates/extension/src/components/shared/UIControls.tsx +199 -0
- package/templates/extension/src/components/shared/index.ts +15 -0
- package/templates/extension/src/components/steps/CanvasStep.tsx +67 -0
- package/templates/extension/src/components/steps/ClipboardStep.tsx +167 -0
- package/templates/extension/src/components/steps/ConfigStep.tsx +63 -0
- package/templates/extension/src/components/steps/EventsStep.tsx +69 -0
- package/templates/extension/src/components/steps/InfoStep.tsx +70 -0
- package/templates/extension/src/components/steps/NetworkStep.tsx +70 -0
- package/templates/extension/src/components/steps/StorageStep.tsx +61 -0
- package/templates/extension/src/components/steps/UIStep.tsx +70 -0
- package/templates/extension/src/hooks/useDoe.ts +93 -0
- package/templates/extension/src/hooks/useOnboarding.ts +264 -0
- package/templates/extension/src/hooks/usePointerHandlers.ts +105 -0
- package/templates/extension/src/main.tsx +18 -0
- package/templates/extension/src/styles.ts +265 -0
- package/templates/extension/tsconfig.json +28 -0
- package/templates/extension/vite.config.ts +32 -0
- package/templates/theme/README.md +132 -0
- package/templates/theme/manifest.json +19 -0
- package/templates/theme/package.json +16 -0
- package/templates/theme/styles/.gitkeep +2 -0
- package/templates/theme/themes/theme.json +32 -0
- package/templates/theme/vite-plugin-doe-theme.ts +53 -0
- package/templates/theme/vite.config.ts +10 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ConfigStep - Onboarding step demonstrating Config API
|
|
3
|
+
*
|
|
4
|
+
* Uses shared ConfigControls component for DRY code.
|
|
5
|
+
*/
|
|
6
|
+
import React, { useState } from "react";
|
|
7
|
+
import type { DOEExtensionAPI } from "doe-sdk/runtime";
|
|
8
|
+
import { StepContainer } from "../StepContainer";
|
|
9
|
+
import { STEP_INFO } from "../../hooks/useOnboarding";
|
|
10
|
+
import { ConfigControls } from "../shared";
|
|
11
|
+
|
|
12
|
+
export interface ConfigStepProps {
|
|
13
|
+
api: DOEExtensionAPI;
|
|
14
|
+
stepNumber: number;
|
|
15
|
+
totalSteps: number;
|
|
16
|
+
onPrev: () => void;
|
|
17
|
+
onNext: () => void;
|
|
18
|
+
isLastStep?: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function ConfigStep({
|
|
22
|
+
api,
|
|
23
|
+
stepNumber,
|
|
24
|
+
totalSteps,
|
|
25
|
+
onPrev,
|
|
26
|
+
onNext,
|
|
27
|
+
isLastStep,
|
|
28
|
+
}: ConfigStepProps): React.ReactElement {
|
|
29
|
+
const [result, setResult] = useState<string>("");
|
|
30
|
+
|
|
31
|
+
const { title, description, icon } = STEP_INFO.config;
|
|
32
|
+
|
|
33
|
+
const codeExample = `// Get a config value
|
|
34
|
+
const city = await api.config.get<string>("defaultCity");
|
|
35
|
+
|
|
36
|
+
// Set a config value
|
|
37
|
+
await api.config.set("defaultCity", "Tokyo");
|
|
38
|
+
|
|
39
|
+
// Open settings UI
|
|
40
|
+
await api.config.openSettings();
|
|
41
|
+
|
|
42
|
+
// Listen for config changes
|
|
43
|
+
api.events.onConfigChange(({ key, value }) => {
|
|
44
|
+
console.log(\`Config \${key} changed to \${value}\`);
|
|
45
|
+
});`;
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<StepContainer
|
|
49
|
+
title={title}
|
|
50
|
+
description={description}
|
|
51
|
+
icon={icon}
|
|
52
|
+
stepNumber={stepNumber}
|
|
53
|
+
totalSteps={totalSteps}
|
|
54
|
+
onPrev={onPrev}
|
|
55
|
+
onNext={onNext}
|
|
56
|
+
isLastStep={isLastStep}
|
|
57
|
+
codeExample={codeExample}
|
|
58
|
+
result={result}
|
|
59
|
+
>
|
|
60
|
+
<ConfigControls api={api} onResult={setResult} />
|
|
61
|
+
</StepContainer>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EventsStep - Onboarding step demonstrating Events API
|
|
3
|
+
*
|
|
4
|
+
* Uses shared EventsControls component for DRY code.
|
|
5
|
+
*/
|
|
6
|
+
import React, { useState } from "react";
|
|
7
|
+
import type { DOEExtensionAPI } from "doe-sdk/runtime";
|
|
8
|
+
import { StepContainer } from "../StepContainer";
|
|
9
|
+
import { STEP_INFO } from "../../hooks/useOnboarding";
|
|
10
|
+
import { EventsControls } from "../shared";
|
|
11
|
+
|
|
12
|
+
export interface EventsStepProps {
|
|
13
|
+
api: DOEExtensionAPI;
|
|
14
|
+
stepNumber: number;
|
|
15
|
+
totalSteps: number;
|
|
16
|
+
onPrev: () => void;
|
|
17
|
+
onNext: () => void;
|
|
18
|
+
isLastStep?: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function EventsStep({
|
|
22
|
+
api,
|
|
23
|
+
stepNumber,
|
|
24
|
+
totalSteps,
|
|
25
|
+
onPrev,
|
|
26
|
+
onNext,
|
|
27
|
+
isLastStep,
|
|
28
|
+
}: EventsStepProps): React.ReactElement {
|
|
29
|
+
const [result, setResult] = useState<string>("Listening for events...");
|
|
30
|
+
|
|
31
|
+
const { title, description, icon } = STEP_INFO.events;
|
|
32
|
+
|
|
33
|
+
const codeExample = `// Selection changes
|
|
34
|
+
const unsub1 = api.events.onSelectionChange((payload) => {
|
|
35
|
+
console.log("Selected shapes:", payload.shapeIds);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// Canvas changes (create, update, delete)
|
|
39
|
+
const unsub2 = api.events.onCanvasChange((payload) => {
|
|
40
|
+
console.log(\`\${payload.type}: \${payload.shapeIds.length} shapes\`);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// Theme changes
|
|
44
|
+
const unsub3 = api.events.onThemeChange((payload) => {
|
|
45
|
+
console.log("Theme changed to:", payload.mode);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// Clean up when done
|
|
49
|
+
unsub1();
|
|
50
|
+
unsub2();
|
|
51
|
+
unsub3();`;
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<StepContainer
|
|
55
|
+
title={title}
|
|
56
|
+
description={description}
|
|
57
|
+
icon={icon}
|
|
58
|
+
stepNumber={stepNumber}
|
|
59
|
+
totalSteps={totalSteps}
|
|
60
|
+
onPrev={onPrev}
|
|
61
|
+
onNext={onNext}
|
|
62
|
+
isLastStep={isLastStep}
|
|
63
|
+
codeExample={codeExample}
|
|
64
|
+
result={result}
|
|
65
|
+
>
|
|
66
|
+
<EventsControls api={api} onResult={setResult} />
|
|
67
|
+
</StepContainer>
|
|
68
|
+
);
|
|
69
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* InfoStep - Onboarding step demonstrating Workspace + Theme APIs
|
|
3
|
+
*
|
|
4
|
+
* Uses shared InfoControls component for DRY code.
|
|
5
|
+
*/
|
|
6
|
+
import React, { useState } from "react";
|
|
7
|
+
import type { DOEExtensionAPI } from "doe-sdk/runtime";
|
|
8
|
+
import { StepContainer } from "../StepContainer";
|
|
9
|
+
import { STEP_INFO } from "../../hooks/useOnboarding";
|
|
10
|
+
import { InfoControls } from "../shared";
|
|
11
|
+
|
|
12
|
+
export interface InfoStepProps {
|
|
13
|
+
api: DOEExtensionAPI;
|
|
14
|
+
stepNumber: number;
|
|
15
|
+
totalSteps: number;
|
|
16
|
+
onPrev: () => void;
|
|
17
|
+
onNext: () => void;
|
|
18
|
+
isLastStep?: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function InfoStep({
|
|
22
|
+
api,
|
|
23
|
+
stepNumber,
|
|
24
|
+
totalSteps,
|
|
25
|
+
onPrev,
|
|
26
|
+
onNext,
|
|
27
|
+
isLastStep,
|
|
28
|
+
}: InfoStepProps): React.ReactElement {
|
|
29
|
+
const [result, setResult] = useState<string>("");
|
|
30
|
+
|
|
31
|
+
const { title, description, icon } = STEP_INFO.info;
|
|
32
|
+
|
|
33
|
+
const codeExample = `// Get workspace information
|
|
34
|
+
const workspace = await api.workspace.getInfo();
|
|
35
|
+
console.log("Workspace:", workspace.name);
|
|
36
|
+
|
|
37
|
+
// Get current user
|
|
38
|
+
const user = await api.workspace.getCurrentUser();
|
|
39
|
+
if (user) {
|
|
40
|
+
console.log("User:", user.displayName);
|
|
41
|
+
console.log("Avatar:", user.avatarUrl);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Get current theme
|
|
45
|
+
const theme = await api.ui.getTheme();
|
|
46
|
+
console.log("Theme mode:", theme.mode);
|
|
47
|
+
console.log("Colors:", theme.colors);
|
|
48
|
+
|
|
49
|
+
// Listen for theme changes
|
|
50
|
+
api.events.onThemeChange((payload) => {
|
|
51
|
+
console.log("Theme changed to:", payload.mode);
|
|
52
|
+
});`;
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<StepContainer
|
|
56
|
+
title={title}
|
|
57
|
+
description={description}
|
|
58
|
+
icon={icon}
|
|
59
|
+
stepNumber={stepNumber}
|
|
60
|
+
totalSteps={totalSteps}
|
|
61
|
+
onPrev={onPrev}
|
|
62
|
+
onNext={onNext}
|
|
63
|
+
isLastStep={isLastStep}
|
|
64
|
+
codeExample={codeExample}
|
|
65
|
+
result={result}
|
|
66
|
+
>
|
|
67
|
+
<InfoControls api={api} onResult={setResult} />
|
|
68
|
+
</StepContainer>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NetworkStep - Onboarding step demonstrating Network API
|
|
3
|
+
*
|
|
4
|
+
* Uses shared NetworkControls component for DRY code.
|
|
5
|
+
*/
|
|
6
|
+
import React, { useState } from "react";
|
|
7
|
+
import type { DOEExtensionAPI } from "doe-sdk/runtime";
|
|
8
|
+
import { StepContainer } from "../StepContainer";
|
|
9
|
+
import { STEP_INFO } from "../../hooks/useOnboarding";
|
|
10
|
+
import { NetworkControls } from "../shared";
|
|
11
|
+
|
|
12
|
+
export interface NetworkStepProps {
|
|
13
|
+
api: DOEExtensionAPI;
|
|
14
|
+
stepNumber: number;
|
|
15
|
+
totalSteps: number;
|
|
16
|
+
onPrev: () => void;
|
|
17
|
+
onNext: () => void;
|
|
18
|
+
isLastStep?: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function NetworkStep({
|
|
22
|
+
api,
|
|
23
|
+
stepNumber,
|
|
24
|
+
totalSteps,
|
|
25
|
+
onPrev,
|
|
26
|
+
onNext,
|
|
27
|
+
isLastStep,
|
|
28
|
+
}: NetworkStepProps): React.ReactElement {
|
|
29
|
+
const [result, setResult] = useState<string>("");
|
|
30
|
+
|
|
31
|
+
const { title, description, icon } = STEP_INFO.network;
|
|
32
|
+
|
|
33
|
+
const codeExample = `// Call any external API from your extension
|
|
34
|
+
// (add domains to hostPermissions in manifest.json)
|
|
35
|
+
|
|
36
|
+
// Example: Fetch from GitHub API
|
|
37
|
+
const response = await api.network.fetch(
|
|
38
|
+
"https://api.github.com/users/torvalds",
|
|
39
|
+
{ timeout: 10000 }
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
if (response.ok) {
|
|
43
|
+
const user = await response.json();
|
|
44
|
+
console.log("Profile:", user.name);
|
|
45
|
+
console.log("Repos:", user.public_repos);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Example: Fetch from any REST API
|
|
49
|
+
const jokes = await api.network.fetch(
|
|
50
|
+
"https://icanhazdadjoke.com/",
|
|
51
|
+
{ headers: { Accept: "application/json" } }
|
|
52
|
+
);`;
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<StepContainer
|
|
56
|
+
title={title}
|
|
57
|
+
description={description}
|
|
58
|
+
icon={icon}
|
|
59
|
+
stepNumber={stepNumber}
|
|
60
|
+
totalSteps={totalSteps}
|
|
61
|
+
onPrev={onPrev}
|
|
62
|
+
onNext={onNext}
|
|
63
|
+
isLastStep={isLastStep}
|
|
64
|
+
codeExample={codeExample}
|
|
65
|
+
result={result}
|
|
66
|
+
>
|
|
67
|
+
<NetworkControls api={api} onResult={setResult} />
|
|
68
|
+
</StepContainer>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* StorageStep - Onboarding step demonstrating Storage API
|
|
3
|
+
*
|
|
4
|
+
* Uses shared StorageControls component for DRY code.
|
|
5
|
+
*/
|
|
6
|
+
import React, { useState } from "react";
|
|
7
|
+
import type { DOEExtensionAPI } from "doe-sdk/runtime";
|
|
8
|
+
import { StepContainer } from "../StepContainer";
|
|
9
|
+
import { STEP_INFO } from "../../hooks/useOnboarding";
|
|
10
|
+
import { StorageControls } from "../shared";
|
|
11
|
+
|
|
12
|
+
export interface StorageStepProps {
|
|
13
|
+
api: DOEExtensionAPI;
|
|
14
|
+
stepNumber: number;
|
|
15
|
+
totalSteps: number;
|
|
16
|
+
onPrev: () => void;
|
|
17
|
+
onNext: () => void;
|
|
18
|
+
isLastStep?: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function StorageStep({
|
|
22
|
+
api,
|
|
23
|
+
stepNumber,
|
|
24
|
+
totalSteps,
|
|
25
|
+
onPrev,
|
|
26
|
+
onNext,
|
|
27
|
+
isLastStep,
|
|
28
|
+
}: StorageStepProps): React.ReactElement {
|
|
29
|
+
const [result, setResult] = useState<string>("");
|
|
30
|
+
|
|
31
|
+
const { title, description, icon } = STEP_INFO.storage;
|
|
32
|
+
|
|
33
|
+
const codeExample = `// Save a value
|
|
34
|
+
await api.storage.set("myKey", "myValue");
|
|
35
|
+
|
|
36
|
+
// Load a value
|
|
37
|
+
const value = await api.storage.get<string>("myKey");
|
|
38
|
+
|
|
39
|
+
// Delete a value
|
|
40
|
+
await api.storage.delete("myKey");
|
|
41
|
+
|
|
42
|
+
// List all keys
|
|
43
|
+
const keys = await api.storage.keys();`;
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<StepContainer
|
|
47
|
+
title={title}
|
|
48
|
+
description={description}
|
|
49
|
+
icon={icon}
|
|
50
|
+
stepNumber={stepNumber}
|
|
51
|
+
totalSteps={totalSteps}
|
|
52
|
+
onPrev={onPrev}
|
|
53
|
+
onNext={onNext}
|
|
54
|
+
isLastStep={isLastStep}
|
|
55
|
+
codeExample={codeExample}
|
|
56
|
+
result={result}
|
|
57
|
+
>
|
|
58
|
+
<StorageControls api={api} onResult={setResult} />
|
|
59
|
+
</StepContainer>
|
|
60
|
+
);
|
|
61
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UIStep - Onboarding step demonstrating UI API
|
|
3
|
+
*
|
|
4
|
+
* Uses shared UIControls component for DRY code.
|
|
5
|
+
*/
|
|
6
|
+
import React, { useState } from "react";
|
|
7
|
+
import type { DOEExtensionAPI } from "doe-sdk/runtime";
|
|
8
|
+
import { StepContainer } from "../StepContainer";
|
|
9
|
+
import { STEP_INFO } from "../../hooks/useOnboarding";
|
|
10
|
+
import { UIControls } from "../shared";
|
|
11
|
+
|
|
12
|
+
export interface UIStepProps {
|
|
13
|
+
api: DOEExtensionAPI;
|
|
14
|
+
stepNumber: number;
|
|
15
|
+
totalSteps: number;
|
|
16
|
+
onPrev: () => void;
|
|
17
|
+
onNext: () => void;
|
|
18
|
+
isLastStep?: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function UIStep({
|
|
22
|
+
api,
|
|
23
|
+
stepNumber,
|
|
24
|
+
totalSteps,
|
|
25
|
+
onPrev,
|
|
26
|
+
onNext,
|
|
27
|
+
isLastStep,
|
|
28
|
+
}: UIStepProps): React.ReactElement {
|
|
29
|
+
const [result, setResult] = useState<string>("");
|
|
30
|
+
|
|
31
|
+
const { title, description, icon } = STEP_INFO.ui;
|
|
32
|
+
|
|
33
|
+
const codeExample = `// Show right-side panel
|
|
34
|
+
await api.ui.showPanel({ title: "My Panel", width: 400 });
|
|
35
|
+
await api.ui.hidePanel();
|
|
36
|
+
|
|
37
|
+
// Show centered modal dialog
|
|
38
|
+
await api.ui.showModal({ title: "My Modal", width: 500, height: 400 });
|
|
39
|
+
await api.ui.hideModal();
|
|
40
|
+
|
|
41
|
+
// Show toast notifications
|
|
42
|
+
await api.ui.showToast("Operation complete!", {
|
|
43
|
+
type: "success", // "info" | "success" | "warning" | "error"
|
|
44
|
+
duration: 3000, // milliseconds
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Show confirmation dialog
|
|
48
|
+
const confirmed = await api.ui.confirm("Delete this item?", {
|
|
49
|
+
title: "Confirm Delete",
|
|
50
|
+
confirmText: "Delete",
|
|
51
|
+
cancelText: "Keep",
|
|
52
|
+
});`;
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<StepContainer
|
|
56
|
+
title={title}
|
|
57
|
+
description={description}
|
|
58
|
+
icon={icon}
|
|
59
|
+
stepNumber={stepNumber}
|
|
60
|
+
totalSteps={totalSteps}
|
|
61
|
+
onPrev={onPrev}
|
|
62
|
+
onNext={onNext}
|
|
63
|
+
isLastStep={isLastStep}
|
|
64
|
+
codeExample={codeExample}
|
|
65
|
+
result={result}
|
|
66
|
+
>
|
|
67
|
+
<UIControls api={api} onResult={setResult} />
|
|
68
|
+
</StepContainer>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useDoe - React Hook for DOE Extension API
|
|
3
|
+
*
|
|
4
|
+
* Wraps the official SDK runtime initializer and provides
|
|
5
|
+
* React-friendly state (`isReady`, `error`) for extension apps.
|
|
6
|
+
*/
|
|
7
|
+
import { useState, useEffect, useSyncExternalStore } from "react";
|
|
8
|
+
import {
|
|
9
|
+
initializeExtension,
|
|
10
|
+
type DOEExtensionAPI,
|
|
11
|
+
} from "doe-sdk/runtime";
|
|
12
|
+
|
|
13
|
+
// ============================================================================
|
|
14
|
+
// REACT INTEGRATION
|
|
15
|
+
// ============================================================================
|
|
16
|
+
|
|
17
|
+
let globalApi: DOEExtensionAPI | null = null;
|
|
18
|
+
let apiInitPromise: Promise<DOEExtensionAPI> | null = null;
|
|
19
|
+
let initError: Error | null = null;
|
|
20
|
+
const subscribers = new Set<() => void>();
|
|
21
|
+
|
|
22
|
+
// Cached snapshot for useSyncExternalStore (must be referentially stable)
|
|
23
|
+
let cachedSnapshot: { api: DOEExtensionAPI | null; error: Error | null } = { api: null, error: null };
|
|
24
|
+
|
|
25
|
+
function updateSnapshot(): void {
|
|
26
|
+
cachedSnapshot = { api: globalApi, error: initError };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function notifySubscribers(): void {
|
|
30
|
+
updateSnapshot();
|
|
31
|
+
for (const sub of subscribers) sub();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function initializeApi(): Promise<DOEExtensionAPI> {
|
|
35
|
+
if (globalApi) return globalApi;
|
|
36
|
+
if (apiInitPromise) return apiInitPromise;
|
|
37
|
+
|
|
38
|
+
apiInitPromise = initializeExtension()
|
|
39
|
+
.then((api) => {
|
|
40
|
+
globalApi = api;
|
|
41
|
+
notifySubscribers();
|
|
42
|
+
return api;
|
|
43
|
+
})
|
|
44
|
+
.catch((error) => {
|
|
45
|
+
initError = error instanceof Error ? error : new Error(String(error));
|
|
46
|
+
notifySubscribers();
|
|
47
|
+
throw initError;
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
return apiInitPromise;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function getApiSnapshot() {
|
|
54
|
+
return cachedSnapshot;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function subscribeToApi(callback: () => void): () => void {
|
|
58
|
+
subscribers.add(callback);
|
|
59
|
+
return () => subscribers.delete(callback);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// ============================================================================
|
|
63
|
+
// HOOK
|
|
64
|
+
// ============================================================================
|
|
65
|
+
|
|
66
|
+
export interface UseDoeResult {
|
|
67
|
+
api: DOEExtensionAPI | null;
|
|
68
|
+
isReady: boolean;
|
|
69
|
+
error: Error | null;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function useDoe(): UseDoeResult {
|
|
73
|
+
const [isInitializing, setIsInitializing] = useState(!globalApi);
|
|
74
|
+
|
|
75
|
+
const { api, error } = useSyncExternalStore(
|
|
76
|
+
subscribeToApi,
|
|
77
|
+
getApiSnapshot,
|
|
78
|
+
getApiSnapshot
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
useEffect(() => {
|
|
82
|
+
if (!globalApi && !apiInitPromise) {
|
|
83
|
+
setIsInitializing(true);
|
|
84
|
+
initializeApi().finally(() => setIsInitializing(false));
|
|
85
|
+
}
|
|
86
|
+
}, []);
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
api,
|
|
90
|
+
isReady: api !== null && !isInitializing,
|
|
91
|
+
error,
|
|
92
|
+
};
|
|
93
|
+
}
|