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,264 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useOnboarding - Onboarding State Management Hook
|
|
3
|
+
*
|
|
4
|
+
* Manages onboarding flow state with persistence via DOE storage API.
|
|
5
|
+
* Supports step navigation, progress tracking, and skip functionality.
|
|
6
|
+
*/
|
|
7
|
+
import { useState, useCallback, useEffect } from "react";
|
|
8
|
+
import type { DOEExtensionAPI } from "doe-sdk/runtime";
|
|
9
|
+
|
|
10
|
+
// ============================================================================
|
|
11
|
+
// TYPES
|
|
12
|
+
// ============================================================================
|
|
13
|
+
|
|
14
|
+
export type OnboardingScreen = "welcome" | "steps" | "complete" | "playground";
|
|
15
|
+
|
|
16
|
+
export type StepId =
|
|
17
|
+
| "canvas"
|
|
18
|
+
| "storage"
|
|
19
|
+
| "config"
|
|
20
|
+
| "ui"
|
|
21
|
+
| "clipboard"
|
|
22
|
+
| "events"
|
|
23
|
+
| "network"
|
|
24
|
+
| "info";
|
|
25
|
+
|
|
26
|
+
export interface OnboardingState {
|
|
27
|
+
/** Current screen being displayed */
|
|
28
|
+
screen: OnboardingScreen;
|
|
29
|
+
/** Current step index (0-based) when in steps screen */
|
|
30
|
+
currentStep: number;
|
|
31
|
+
/** Completed step IDs */
|
|
32
|
+
completedSteps: StepId[];
|
|
33
|
+
/** Whether onboarding was skipped */
|
|
34
|
+
skipped: boolean;
|
|
35
|
+
/** Whether state has been loaded from storage */
|
|
36
|
+
isLoaded: boolean;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface UseOnboardingResult {
|
|
40
|
+
state: OnboardingState;
|
|
41
|
+
/** Navigate to a specific screen */
|
|
42
|
+
goToScreen: (screen: OnboardingScreen) => void;
|
|
43
|
+
/** Go to next step */
|
|
44
|
+
nextStep: () => void;
|
|
45
|
+
/** Go to previous step */
|
|
46
|
+
prevStep: () => void;
|
|
47
|
+
/** Mark current step as completed and advance */
|
|
48
|
+
completeStep: () => void;
|
|
49
|
+
/** Skip onboarding and go to playground */
|
|
50
|
+
skip: () => void;
|
|
51
|
+
/** Restart onboarding from welcome */
|
|
52
|
+
restart: () => void;
|
|
53
|
+
/** Total number of steps */
|
|
54
|
+
totalSteps: number;
|
|
55
|
+
/** Whether all steps are completed */
|
|
56
|
+
isComplete: boolean;
|
|
57
|
+
/** Get current step ID */
|
|
58
|
+
currentStepId: StepId;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// ============================================================================
|
|
62
|
+
// CONSTANTS
|
|
63
|
+
// ============================================================================
|
|
64
|
+
|
|
65
|
+
const STORAGE_KEY = "onboarding_state";
|
|
66
|
+
|
|
67
|
+
export const STEPS: StepId[] = [
|
|
68
|
+
"canvas",
|
|
69
|
+
"storage",
|
|
70
|
+
"config",
|
|
71
|
+
"ui",
|
|
72
|
+
"clipboard",
|
|
73
|
+
"events",
|
|
74
|
+
"network",
|
|
75
|
+
"info",
|
|
76
|
+
];
|
|
77
|
+
|
|
78
|
+
export const STEP_INFO: Record<
|
|
79
|
+
StepId,
|
|
80
|
+
{ title: string; description: string; icon: string }
|
|
81
|
+
> = {
|
|
82
|
+
canvas: {
|
|
83
|
+
title: "Canvas API",
|
|
84
|
+
description: "Navigate the canvas and query selected shapes",
|
|
85
|
+
icon: "🎨",
|
|
86
|
+
},
|
|
87
|
+
storage: {
|
|
88
|
+
title: "Storage API",
|
|
89
|
+
description: "Persist data locally with key-value storage",
|
|
90
|
+
icon: "💾",
|
|
91
|
+
},
|
|
92
|
+
config: {
|
|
93
|
+
title: "Config API",
|
|
94
|
+
description: "Manage user-configurable settings",
|
|
95
|
+
icon: "⚙️",
|
|
96
|
+
},
|
|
97
|
+
ui: {
|
|
98
|
+
title: "UI API",
|
|
99
|
+
description: "Show notifications and confirmation dialogs",
|
|
100
|
+
icon: "🔔",
|
|
101
|
+
},
|
|
102
|
+
clipboard: {
|
|
103
|
+
title: "Clipboard API",
|
|
104
|
+
description: "Read and write to the system clipboard",
|
|
105
|
+
icon: "📋",
|
|
106
|
+
},
|
|
107
|
+
events: {
|
|
108
|
+
title: "Events API",
|
|
109
|
+
description: "React to selection and canvas changes",
|
|
110
|
+
icon: "📡",
|
|
111
|
+
},
|
|
112
|
+
network: {
|
|
113
|
+
title: "Network API",
|
|
114
|
+
description: "Call external APIs like GitHub, weather services, and more",
|
|
115
|
+
icon: "🌐",
|
|
116
|
+
},
|
|
117
|
+
info: {
|
|
118
|
+
title: "Workspace & Theme",
|
|
119
|
+
description: "Access workspace info and theme tokens",
|
|
120
|
+
icon: "ℹ️",
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
// ============================================================================
|
|
125
|
+
// INITIAL STATE
|
|
126
|
+
// ============================================================================
|
|
127
|
+
|
|
128
|
+
const initialState: OnboardingState = {
|
|
129
|
+
screen: "welcome",
|
|
130
|
+
currentStep: 0,
|
|
131
|
+
completedSteps: [],
|
|
132
|
+
skipped: false,
|
|
133
|
+
isLoaded: false,
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
// ============================================================================
|
|
137
|
+
// HOOK
|
|
138
|
+
// ============================================================================
|
|
139
|
+
|
|
140
|
+
export function useOnboarding(api: DOEExtensionAPI | null): UseOnboardingResult {
|
|
141
|
+
const [state, setState] = useState<OnboardingState>(initialState);
|
|
142
|
+
|
|
143
|
+
// Load state from storage on mount
|
|
144
|
+
useEffect(() => {
|
|
145
|
+
if (!api) return;
|
|
146
|
+
|
|
147
|
+
api.storage.get<OnboardingState>(STORAGE_KEY).then((savedState) => {
|
|
148
|
+
if (savedState && savedState.screen) {
|
|
149
|
+
setState({ ...savedState, isLoaded: true });
|
|
150
|
+
} else {
|
|
151
|
+
setState((s) => ({ ...s, isLoaded: true }));
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
}, [api]);
|
|
155
|
+
|
|
156
|
+
// Persist state to storage
|
|
157
|
+
const persistState = useCallback(
|
|
158
|
+
(newState: OnboardingState) => {
|
|
159
|
+
if (!api) return;
|
|
160
|
+
api.storage.set(STORAGE_KEY, newState);
|
|
161
|
+
},
|
|
162
|
+
[api]
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
const goToScreen = useCallback(
|
|
166
|
+
(screen: OnboardingScreen) => {
|
|
167
|
+
setState((prev) => {
|
|
168
|
+
const newState = { ...prev, screen };
|
|
169
|
+
persistState(newState);
|
|
170
|
+
return newState;
|
|
171
|
+
});
|
|
172
|
+
},
|
|
173
|
+
[persistState]
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
const nextStep = useCallback(() => {
|
|
177
|
+
setState((prev) => {
|
|
178
|
+
if (prev.currentStep >= STEPS.length - 1) {
|
|
179
|
+
// Move to complete screen
|
|
180
|
+
const newState = { ...prev, screen: "complete" as OnboardingScreen };
|
|
181
|
+
persistState(newState);
|
|
182
|
+
return newState;
|
|
183
|
+
}
|
|
184
|
+
const newState = { ...prev, currentStep: prev.currentStep + 1 };
|
|
185
|
+
persistState(newState);
|
|
186
|
+
return newState;
|
|
187
|
+
});
|
|
188
|
+
}, [persistState]);
|
|
189
|
+
|
|
190
|
+
const prevStep = useCallback(() => {
|
|
191
|
+
setState((prev) => {
|
|
192
|
+
if (prev.currentStep <= 0) return prev;
|
|
193
|
+
const newState = { ...prev, currentStep: prev.currentStep - 1 };
|
|
194
|
+
persistState(newState);
|
|
195
|
+
return newState;
|
|
196
|
+
});
|
|
197
|
+
}, [persistState]);
|
|
198
|
+
|
|
199
|
+
const completeStep = useCallback(() => {
|
|
200
|
+
setState((prev) => {
|
|
201
|
+
const stepId = STEPS[prev.currentStep];
|
|
202
|
+
const alreadyCompleted = prev.completedSteps.includes(stepId);
|
|
203
|
+
const completedSteps = alreadyCompleted
|
|
204
|
+
? prev.completedSteps
|
|
205
|
+
: [...prev.completedSteps, stepId];
|
|
206
|
+
|
|
207
|
+
if (prev.currentStep >= STEPS.length - 1) {
|
|
208
|
+
// All steps done
|
|
209
|
+
const newState = {
|
|
210
|
+
...prev,
|
|
211
|
+
completedSteps,
|
|
212
|
+
screen: "complete" as OnboardingScreen,
|
|
213
|
+
};
|
|
214
|
+
persistState(newState);
|
|
215
|
+
return newState;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const newState = {
|
|
219
|
+
...prev,
|
|
220
|
+
completedSteps,
|
|
221
|
+
currentStep: prev.currentStep + 1,
|
|
222
|
+
};
|
|
223
|
+
persistState(newState);
|
|
224
|
+
return newState;
|
|
225
|
+
});
|
|
226
|
+
}, [persistState]);
|
|
227
|
+
|
|
228
|
+
const skip = useCallback(() => {
|
|
229
|
+
setState((prev) => {
|
|
230
|
+
const newState = {
|
|
231
|
+
...prev,
|
|
232
|
+
skipped: true,
|
|
233
|
+
screen: "playground" as OnboardingScreen,
|
|
234
|
+
};
|
|
235
|
+
persistState(newState);
|
|
236
|
+
return newState;
|
|
237
|
+
});
|
|
238
|
+
}, [persistState]);
|
|
239
|
+
|
|
240
|
+
const restart = useCallback(() => {
|
|
241
|
+
const newState = {
|
|
242
|
+
...initialState,
|
|
243
|
+
isLoaded: true,
|
|
244
|
+
};
|
|
245
|
+
persistState(newState);
|
|
246
|
+
setState(newState);
|
|
247
|
+
}, [persistState]);
|
|
248
|
+
|
|
249
|
+
const isComplete = state.completedSteps.length === STEPS.length;
|
|
250
|
+
const currentStepId = STEPS[state.currentStep];
|
|
251
|
+
|
|
252
|
+
return {
|
|
253
|
+
state,
|
|
254
|
+
goToScreen,
|
|
255
|
+
nextStep,
|
|
256
|
+
prevStep,
|
|
257
|
+
completeStep,
|
|
258
|
+
skip,
|
|
259
|
+
restart,
|
|
260
|
+
totalSteps: STEPS.length,
|
|
261
|
+
isComplete,
|
|
262
|
+
currentStepId,
|
|
263
|
+
};
|
|
264
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pointer Handler Hooks for DOE Extensions
|
|
3
|
+
*
|
|
4
|
+
* These hooks help manage pointer events in extension UIs to ensure
|
|
5
|
+
* proper interaction between extension content and the DOE canvas.
|
|
6
|
+
*
|
|
7
|
+
* Extensions use `pointerEvents: "auto"`, which means the extension captures
|
|
8
|
+
* all pointer events. For interactive areas (buttons, inputs, scrollable content),
|
|
9
|
+
* you must use stopPropagation() to prevent those events from triggering
|
|
10
|
+
* canvas drag or other canvas actions.
|
|
11
|
+
*/
|
|
12
|
+
import { useCallback, useEffect, type RefObject } from "react";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Hook for interactive areas that should NOT start a canvas drag.
|
|
16
|
+
* Use on buttons, inputs, scrollable content, dropdown menus, etc.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```tsx
|
|
20
|
+
* function MyExtension() {
|
|
21
|
+
* const handleInteractive = useInteractivePointerDown();
|
|
22
|
+
*
|
|
23
|
+
* return (
|
|
24
|
+
* <div>
|
|
25
|
+
* <button onPointerDown={handleInteractive}>Click me</button>
|
|
26
|
+
* <input onPointerDown={handleInteractive} />
|
|
27
|
+
* <textarea onPointerDown={handleInteractive} />
|
|
28
|
+
* </div>
|
|
29
|
+
* );
|
|
30
|
+
* }
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export function useInteractivePointerDown(): (e: React.PointerEvent) => void {
|
|
34
|
+
return useCallback((e: React.PointerEvent) => {
|
|
35
|
+
e.stopPropagation();
|
|
36
|
+
}, []);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Hook to prevent canvas zoom when scrolling inside extension.
|
|
41
|
+
* Use on scrollable containers to ensure scroll wheel events
|
|
42
|
+
* scroll the content instead of zooming the canvas.
|
|
43
|
+
*
|
|
44
|
+
* @param ref - Reference to the scrollable element
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```tsx
|
|
48
|
+
* function MyExtension() {
|
|
49
|
+
* const scrollRef = useRef<HTMLDivElement>(null);
|
|
50
|
+
* usePreventCanvasZoom(scrollRef);
|
|
51
|
+
*
|
|
52
|
+
* return (
|
|
53
|
+
* <div ref={scrollRef} className="overflow-auto h-64">
|
|
54
|
+
* {/* Long scrollable content *\/}
|
|
55
|
+
* <div className="h-[1000px]">Content...</div>
|
|
56
|
+
* </div>
|
|
57
|
+
* );
|
|
58
|
+
* }
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
export function usePreventCanvasZoom(ref: RefObject<HTMLElement | null>): void {
|
|
62
|
+
useEffect(() => {
|
|
63
|
+
const el = ref.current;
|
|
64
|
+
if (!el) return;
|
|
65
|
+
|
|
66
|
+
const handleWheel = (e: WheelEvent) => {
|
|
67
|
+
e.stopPropagation();
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
el.addEventListener("wheel", handleWheel, { capture: true, passive: false });
|
|
71
|
+
return () => el.removeEventListener("wheel", handleWheel, { capture: true });
|
|
72
|
+
}, [ref]);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Combined hook for scrollable interactive areas.
|
|
77
|
+
* Provides both pointer down handler and wheel event blocking.
|
|
78
|
+
*
|
|
79
|
+
* @param ref - Reference to the scrollable element
|
|
80
|
+
* @returns Handler for onPointerDown events
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* ```tsx
|
|
84
|
+
* function MyExtension() {
|
|
85
|
+
* const scrollRef = useRef<HTMLDivElement>(null);
|
|
86
|
+
* const handleInteractive = useScrollableArea(scrollRef);
|
|
87
|
+
*
|
|
88
|
+
* return (
|
|
89
|
+
* <div
|
|
90
|
+
* ref={scrollRef}
|
|
91
|
+
* className="overflow-auto"
|
|
92
|
+
* onPointerDown={handleInteractive}
|
|
93
|
+
* >
|
|
94
|
+
* Scrollable content...
|
|
95
|
+
* </div>
|
|
96
|
+
* );
|
|
97
|
+
* }
|
|
98
|
+
* ```
|
|
99
|
+
*/
|
|
100
|
+
export function useScrollableArea(
|
|
101
|
+
ref: RefObject<HTMLElement | null>
|
|
102
|
+
): (e: React.PointerEvent) => void {
|
|
103
|
+
usePreventCanvasZoom(ref);
|
|
104
|
+
return useInteractivePointerDown();
|
|
105
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* {{displayName}} - React Entry Point
|
|
3
|
+
*
|
|
4
|
+
* Renders React immediately. DOE connection is handled by useDoe hook.
|
|
5
|
+
* This allows the extension to work both standalone (for development)
|
|
6
|
+
* and inside DOE (for production).
|
|
7
|
+
*/
|
|
8
|
+
import { createRoot } from "react-dom/client";
|
|
9
|
+
import { App } from "./App";
|
|
10
|
+
|
|
11
|
+
// Mount React immediately
|
|
12
|
+
const container = document.getElementById("root");
|
|
13
|
+
if (!container) {
|
|
14
|
+
throw new Error("Root element not found");
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const root = createRoot(container);
|
|
18
|
+
root.render(<App />);
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Styles for Extension Template
|
|
3
|
+
*
|
|
4
|
+
* CSS custom properties and reusable style objects for consistent theming.
|
|
5
|
+
* Uses inline styles (consistent with existing template pattern).
|
|
6
|
+
*/
|
|
7
|
+
import type { CSSProperties } from "react";
|
|
8
|
+
|
|
9
|
+
// ============================================================================
|
|
10
|
+
// SPACING SCALE (4px base)
|
|
11
|
+
// ============================================================================
|
|
12
|
+
export const spacing = {
|
|
13
|
+
xs: 4,
|
|
14
|
+
sm: 8,
|
|
15
|
+
md: 16,
|
|
16
|
+
lg: 24,
|
|
17
|
+
xl: 32,
|
|
18
|
+
xxl: 48,
|
|
19
|
+
} as const;
|
|
20
|
+
|
|
21
|
+
// ============================================================================
|
|
22
|
+
// COLORS
|
|
23
|
+
// ============================================================================
|
|
24
|
+
export const colors = {
|
|
25
|
+
// Primary
|
|
26
|
+
primary: "#3b82f6",
|
|
27
|
+
primaryHover: "#2563eb",
|
|
28
|
+
primaryLight: "#dbeafe",
|
|
29
|
+
|
|
30
|
+
// Success
|
|
31
|
+
success: "#22c55e",
|
|
32
|
+
successLight: "#dcfce7",
|
|
33
|
+
|
|
34
|
+
// Warning
|
|
35
|
+
warning: "#f59e0b",
|
|
36
|
+
warningLight: "#fef3c7",
|
|
37
|
+
|
|
38
|
+
// Error
|
|
39
|
+
error: "#ef4444",
|
|
40
|
+
errorLight: "#fee2e2",
|
|
41
|
+
|
|
42
|
+
// Neutral
|
|
43
|
+
text: "#111827",
|
|
44
|
+
textSecondary: "#6b7280",
|
|
45
|
+
textMuted: "#9ca3af",
|
|
46
|
+
border: "#e5e7eb",
|
|
47
|
+
borderLight: "#f3f4f6",
|
|
48
|
+
background: "#ffffff",
|
|
49
|
+
backgroundSecondary: "#f9fafb",
|
|
50
|
+
backgroundHover: "#f3f4f6",
|
|
51
|
+
backgroundCode: "#1e293b",
|
|
52
|
+
} as const;
|
|
53
|
+
|
|
54
|
+
// ============================================================================
|
|
55
|
+
// TYPOGRAPHY
|
|
56
|
+
// ============================================================================
|
|
57
|
+
export const typography = {
|
|
58
|
+
fontFamily:
|
|
59
|
+
'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',
|
|
60
|
+
sizes: {
|
|
61
|
+
xs: 11,
|
|
62
|
+
sm: 12,
|
|
63
|
+
base: 14,
|
|
64
|
+
lg: 16,
|
|
65
|
+
xl: 20,
|
|
66
|
+
xxl: 24,
|
|
67
|
+
},
|
|
68
|
+
weights: {
|
|
69
|
+
normal: 400,
|
|
70
|
+
medium: 500,
|
|
71
|
+
semibold: 600,
|
|
72
|
+
},
|
|
73
|
+
} as const;
|
|
74
|
+
|
|
75
|
+
// ============================================================================
|
|
76
|
+
// SHARED STYLE OBJECTS
|
|
77
|
+
// ============================================================================
|
|
78
|
+
|
|
79
|
+
export const buttonStyles = {
|
|
80
|
+
primary: {
|
|
81
|
+
padding: `${spacing.sm}px ${spacing.lg}px`,
|
|
82
|
+
background: colors.primary,
|
|
83
|
+
color: "white",
|
|
84
|
+
border: "none",
|
|
85
|
+
borderRadius: 8,
|
|
86
|
+
fontSize: typography.sizes.base,
|
|
87
|
+
fontWeight: typography.weights.medium,
|
|
88
|
+
cursor: "pointer",
|
|
89
|
+
transition: "all 0.15s ease",
|
|
90
|
+
display: "inline-flex",
|
|
91
|
+
alignItems: "center",
|
|
92
|
+
justifyContent: "center",
|
|
93
|
+
gap: spacing.sm,
|
|
94
|
+
} as CSSProperties,
|
|
95
|
+
|
|
96
|
+
secondary: {
|
|
97
|
+
padding: `${spacing.sm}px ${spacing.lg}px`,
|
|
98
|
+
background: "transparent",
|
|
99
|
+
color: colors.textSecondary,
|
|
100
|
+
border: `1px solid ${colors.border}`,
|
|
101
|
+
borderRadius: 8,
|
|
102
|
+
fontSize: typography.sizes.base,
|
|
103
|
+
fontWeight: typography.weights.medium,
|
|
104
|
+
cursor: "pointer",
|
|
105
|
+
transition: "all 0.15s ease",
|
|
106
|
+
display: "inline-flex",
|
|
107
|
+
alignItems: "center",
|
|
108
|
+
justifyContent: "center",
|
|
109
|
+
gap: spacing.sm,
|
|
110
|
+
} as CSSProperties,
|
|
111
|
+
|
|
112
|
+
link: {
|
|
113
|
+
padding: `${spacing.xs}px ${spacing.sm}px`,
|
|
114
|
+
background: "transparent",
|
|
115
|
+
color: colors.textSecondary,
|
|
116
|
+
border: "none",
|
|
117
|
+
fontSize: typography.sizes.sm,
|
|
118
|
+
cursor: "pointer",
|
|
119
|
+
textDecoration: "underline",
|
|
120
|
+
transition: "color 0.15s ease",
|
|
121
|
+
} as CSSProperties,
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
export const inputStyles = {
|
|
125
|
+
base: {
|
|
126
|
+
width: "100%",
|
|
127
|
+
padding: `${spacing.sm}px ${spacing.md}px`,
|
|
128
|
+
border: `1px solid ${colors.border}`,
|
|
129
|
+
borderRadius: 8,
|
|
130
|
+
fontSize: typography.sizes.base,
|
|
131
|
+
outline: "none",
|
|
132
|
+
transition: "border-color 0.15s ease",
|
|
133
|
+
boxSizing: "border-box",
|
|
134
|
+
} as CSSProperties,
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
export const cardStyles = {
|
|
138
|
+
base: {
|
|
139
|
+
background: colors.backgroundSecondary,
|
|
140
|
+
borderRadius: 12,
|
|
141
|
+
padding: spacing.md,
|
|
142
|
+
border: `1px solid ${colors.borderLight}`,
|
|
143
|
+
} as CSSProperties,
|
|
144
|
+
|
|
145
|
+
interactive: {
|
|
146
|
+
background: colors.backgroundSecondary,
|
|
147
|
+
borderRadius: 12,
|
|
148
|
+
padding: spacing.md,
|
|
149
|
+
border: `1px solid ${colors.borderLight}`,
|
|
150
|
+
cursor: "pointer",
|
|
151
|
+
transition: "all 0.15s ease",
|
|
152
|
+
} as CSSProperties,
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
// ============================================================================
|
|
156
|
+
// ANIMATION KEYFRAMES (as CSS string)
|
|
157
|
+
// ============================================================================
|
|
158
|
+
export const animationStyles = `
|
|
159
|
+
@keyframes fadeIn {
|
|
160
|
+
from { opacity: 0; }
|
|
161
|
+
to { opacity: 1; }
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
@keyframes slideInUp {
|
|
165
|
+
from {
|
|
166
|
+
opacity: 0;
|
|
167
|
+
transform: translateY(16px);
|
|
168
|
+
}
|
|
169
|
+
to {
|
|
170
|
+
opacity: 1;
|
|
171
|
+
transform: translateY(0);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
@keyframes slideInLeft {
|
|
176
|
+
from {
|
|
177
|
+
opacity: 0;
|
|
178
|
+
transform: translateX(-16px);
|
|
179
|
+
}
|
|
180
|
+
to {
|
|
181
|
+
opacity: 1;
|
|
182
|
+
transform: translateX(0);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
@keyframes slideInRight {
|
|
187
|
+
from {
|
|
188
|
+
opacity: 0;
|
|
189
|
+
transform: translateX(16px);
|
|
190
|
+
}
|
|
191
|
+
to {
|
|
192
|
+
opacity: 1;
|
|
193
|
+
transform: translateX(0);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
@keyframes pulse {
|
|
198
|
+
0%, 100% { opacity: 1; }
|
|
199
|
+
50% { opacity: 0.5; }
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
@keyframes checkmark {
|
|
203
|
+
0% {
|
|
204
|
+
stroke-dashoffset: 50;
|
|
205
|
+
}
|
|
206
|
+
100% {
|
|
207
|
+
stroke-dashoffset: 0;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
@keyframes scaleIn {
|
|
212
|
+
from {
|
|
213
|
+
opacity: 0;
|
|
214
|
+
transform: scale(0.9);
|
|
215
|
+
}
|
|
216
|
+
to {
|
|
217
|
+
opacity: 1;
|
|
218
|
+
transform: scale(1);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
`;
|
|
222
|
+
|
|
223
|
+
// ============================================================================
|
|
224
|
+
// LAYOUT HELPERS
|
|
225
|
+
// ============================================================================
|
|
226
|
+
export const flexCenter: CSSProperties = {
|
|
227
|
+
display: "flex",
|
|
228
|
+
alignItems: "center",
|
|
229
|
+
justifyContent: "center",
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
export const flexBetween: CSSProperties = {
|
|
233
|
+
display: "flex",
|
|
234
|
+
alignItems: "center",
|
|
235
|
+
justifyContent: "space-between",
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
export const flexColumn: CSSProperties = {
|
|
239
|
+
display: "flex",
|
|
240
|
+
flexDirection: "column",
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
// ============================================================================
|
|
244
|
+
// CODE DISPLAY STYLES
|
|
245
|
+
// ============================================================================
|
|
246
|
+
export const codeStyles = {
|
|
247
|
+
container: {
|
|
248
|
+
background: "#1e1e1e",
|
|
249
|
+
borderRadius: 8,
|
|
250
|
+
padding: spacing.md,
|
|
251
|
+
overflow: "auto",
|
|
252
|
+
fontSize: typography.sizes.sm,
|
|
253
|
+
fontFamily: 'Monaco, Menlo, "Ubuntu Mono", Consolas, monospace',
|
|
254
|
+
lineHeight: 1.5,
|
|
255
|
+
} as CSSProperties,
|
|
256
|
+
|
|
257
|
+
keyword: { color: "#569cd6" },
|
|
258
|
+
string: { color: "#ce9178" },
|
|
259
|
+
comment: { color: "#6a9955" },
|
|
260
|
+
function: { color: "#dcdcaa" },
|
|
261
|
+
variable: { color: "#9cdcfe" },
|
|
262
|
+
property: { color: "#4ec9b0" },
|
|
263
|
+
operator: { color: "#d4d4d4" },
|
|
264
|
+
plain: { color: "#d4d4d4" },
|
|
265
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
7
|
+
"jsx": "react-jsx",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"declaration": false,
|
|
10
|
+
"outDir": "./dist",
|
|
11
|
+
"rootDir": "./src",
|
|
12
|
+
"esModuleInterop": true,
|
|
13
|
+
"skipLibCheck": true,
|
|
14
|
+
"forceConsistentCasingInFileNames": true,
|
|
15
|
+
"noUnusedLocals": true,
|
|
16
|
+
"noUnusedParameters": true,
|
|
17
|
+
"noFallthroughCasesInSwitch": true,
|
|
18
|
+
"resolveJsonModule": true,
|
|
19
|
+
"isolatedModules": true,
|
|
20
|
+
"noEmit": true,
|
|
21
|
+
"paths": {
|
|
22
|
+
"doe-sdk": ["../../dist/index.d.ts"],
|
|
23
|
+
"doe-sdk/*": ["../../dist/*"]
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"include": ["src/**/*"],
|
|
27
|
+
"exclude": ["node_modules", "dist"]
|
|
28
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vite Configuration for DOE Extension
|
|
3
|
+
*
|
|
4
|
+
* Builds the extension as a single HTML + JS bundle that can be loaded in DOE.
|
|
5
|
+
*/
|
|
6
|
+
import { defineConfig } from "vite";
|
|
7
|
+
import react from "@vitejs/plugin-react";
|
|
8
|
+
|
|
9
|
+
export default defineConfig({
|
|
10
|
+
plugins: [react()],
|
|
11
|
+
base: "./", // Use relative paths for DOE custom protocol
|
|
12
|
+
build: {
|
|
13
|
+
outDir: "dist",
|
|
14
|
+
// Inline all assets for simpler loading
|
|
15
|
+
assetsInlineLimit: 100000,
|
|
16
|
+
rollupOptions: {
|
|
17
|
+
output: {
|
|
18
|
+
// Single JS file
|
|
19
|
+
entryFileNames: "assets/[name].js",
|
|
20
|
+
chunkFileNames: "assets/[name].js",
|
|
21
|
+
assetFileNames: "assets/[name].[ext]",
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
target: "esnext",
|
|
25
|
+
minify: true,
|
|
26
|
+
sourcemap: false,
|
|
27
|
+
},
|
|
28
|
+
server: {
|
|
29
|
+
port: 3001,
|
|
30
|
+
strictPort: true,
|
|
31
|
+
},
|
|
32
|
+
});
|