@pie-players/pie-calculator-desmos 0.1.2

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 ADDED
@@ -0,0 +1,285 @@
1
+ # @pie-players/pie-calculator-desmos
2
+
3
+ Desmos calculator provider for PIE Players - Premium graphing, scientific, and basic calculators.
4
+
5
+ ## Features
6
+
7
+ - ✅ Beautiful, intuitive graphing calculators
8
+ - ✅ Interactive expression lists
9
+ - ✅ Scientific and basic calculator modes
10
+ - ✅ State persistence and export
11
+ - ⚠️ Requires Desmos API key from [desmos.com/api](https://www.desmos.com/api)
12
+ - ⚠️ Requires internet connection
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install @pie-players/pie-calculator-desmos
18
+ ```
19
+
20
+ ## How Desmos API Keys Work
21
+
22
+ According to Desmos documentation, the API key should be included when loading the Desmos calculator library:
23
+
24
+ ```html
25
+ <script src="https://www.desmos.com/api/v1.11/calculator.js?apiKey=YOUR_KEY"></script>
26
+ ```
27
+
28
+ However, **this approach exposes your API key in client-side HTML**, which is a security risk for production applications.
29
+
30
+ ## Security Best Practices
31
+
32
+ ### ⚠️ Important Security Considerations
33
+
34
+ While Desmos's documentation shows the API key embedded in the script URL (client-side), this is **NOT SECURE for production** because:
35
+
36
+ 1. Anyone can view your HTML source and see the API key
37
+ 2. The key can be copied and used by others
38
+ 3. You cannot rotate keys without redeploying your entire application
39
+ 4. You have no control over who uses your key
40
+
41
+ ### Our Recommended Patterns
42
+
43
+ This package supports three configuration patterns:
44
+
45
+ #### 1. Development Mode (Direct API Key) - Testing Only
46
+
47
+ Use the demo key or your own key for local development:
48
+
49
+ ```html
50
+ <!-- Load Desmos with demo key -->
51
+ <script src="https://www.desmos.com/api/v1.11/calculator.js?apiKey=REDACTED_API_KEY"></script>
52
+ ```
53
+
54
+ ```typescript
55
+ import { DesmosCalculatorProvider } from '@pie-players/pie-calculator-desmos';
56
+
57
+ const provider = new DesmosCalculatorProvider();
58
+ await provider.initialize(); // Uses the globally loaded Desmos
59
+ ```
60
+
61
+ ⚠️ Only use your real API key like this during development!
62
+
63
+ #### 2. Production Mode (Server-Side Proxy) - ✅ RECOMMENDED
64
+
65
+ For production, use a server-side proxy to keep your API key secure:
66
+
67
+ ```typescript
68
+ const provider = new DesmosCalculatorProvider();
69
+ await provider.initialize({
70
+ proxyEndpoint: '/api/desmos/script-url' // Server returns the script URL with key
71
+ });
72
+ ```
73
+
74
+ Your server endpoint returns a signed or time-limited URL.
75
+
76
+ #### 3. Pre-loaded Library (Client-Side)
77
+
78
+ If you must use client-side loading in production (not recommended), at least load the library yourself and don't pass the key through our package:
79
+
80
+ ```html
81
+ <script src="https://www.desmos.com/api/v1.11/calculator.js?apiKey=YOUR_KEY"></script>
82
+ ```
83
+
84
+ ```typescript
85
+ const provider = new DesmosCalculatorProvider();
86
+ await provider.initialize(); // No key needed, uses window.Desmos
87
+ ```
88
+
89
+ **Note**: This still exposes your key in HTML, but at least it's not in your JavaScript bundle.
90
+
91
+ ## Server-Side Proxy Implementation
92
+
93
+ ### Understanding the Challenge
94
+
95
+ Desmos requires the API key in the script URL when loading the library. To keep your key secure while still working within Desmos's architecture, you need a server-side proxy.
96
+
97
+ ### Option A: Proxy the Desmos Script (Most Secure)
98
+
99
+ Create a server endpoint that proxies the Desmos calculator script with your API key:
100
+
101
+ #### Express.js Example
102
+
103
+ ```javascript
104
+ // server.js
105
+ app.get('/api/desmos/calculator.js', requireAuth, async (req, res) => {
106
+ if (!req.user) {
107
+ return res.status(401).json({ error: 'Unauthorized' });
108
+ }
109
+
110
+ // Fetch Desmos script with your API key server-side
111
+ const desmosUrl = `https://www.desmos.com/api/v1.11/calculator.js?apiKey=${process.env.DESMOS_API_KEY}`;
112
+ const response = await fetch(desmosUrl);
113
+ const script = await response.text();
114
+
115
+ res.setHeader('Content-Type', 'application/javascript');
116
+ res.send(script);
117
+ });
118
+ ```
119
+
120
+ Then load from your proxy in the client:
121
+
122
+ ```html
123
+ <script src="/api/desmos/calculator.js"></script>
124
+ ```
125
+
126
+ ### Option B: Return Signed/Time-Limited URL
127
+
128
+ Create temporary, authenticated URLs that expire:
129
+
130
+ #### Next.js API Route Example
131
+
132
+ ```typescript
133
+ // pages/api/desmos/script-url.ts
134
+ import { getServerSession } from 'next-auth';
135
+ import { sign } from 'jsonwebtoken';
136
+
137
+ export default async function handler(req, res) {
138
+ const session = await getServerSession(req, res);
139
+
140
+ if (!session) {
141
+ return res.status(401).json({ error: 'Unauthorized' });
142
+ }
143
+
144
+ // Create a time-limited token
145
+ const token = sign(
146
+ { userId: session.user.id },
147
+ process.env.JWT_SECRET,
148
+ { expiresIn: '1h' }
149
+ );
150
+
151
+ // Return URL with your API key (only valid for this session)
152
+ res.json({
153
+ scriptUrl: `https://www.desmos.com/api/v1.11/calculator.js?apiKey=${process.env.DESMOS_API_KEY}`,
154
+ expiresAt: Date.now() + 3600000
155
+ });
156
+ }
157
+ ```
158
+
159
+ ### Advantages of Server-Side Proxy
160
+
161
+ 1. **Security**: API key never exposed to client in retrievable form
162
+ 2. **Authentication**: Control who can access Desmos
163
+ 3. **Rate Limiting**: Implement usage limits server-side
164
+ 4. **Usage Tracking**: Monitor calculator usage for billing
165
+ 5. **Key Rotation**: Change keys without redeploying client code
166
+ 6. **Compliance**: Meets security requirements for sensitive data
167
+
168
+ ### Reality Check
169
+
170
+ **Important**: Even with a proxy, if the client loads the Desmos script, a determined user could still inspect network traffic and find the API key embedded in the script content. For true security:
171
+
172
+ 1. Consider if Desmos calculators are necessary for your use case
173
+ 2. Use alternative open-source calculator libraries (like Math.js) when possible
174
+ 3. Contact Desmos at <partnerships@desmos.com> to discuss enterprise security options
175
+ 4. Implement rate limiting and usage monitoring to detect key misuse
176
+
177
+ ## Usage
178
+
179
+ ### Basic Calculator
180
+
181
+ ```typescript
182
+ const provider = new DesmosCalculatorProvider();
183
+ await provider.initialize({ proxyEndpoint: '/api/desmos/token' });
184
+
185
+ const calculator = await provider.createCalculator(
186
+ 'basic',
187
+ document.getElementById('calculator-container')
188
+ );
189
+ ```
190
+
191
+ ### Scientific Calculator
192
+
193
+ ```typescript
194
+ const calculator = await provider.createCalculator(
195
+ 'scientific',
196
+ document.getElementById('calculator-container'),
197
+ {
198
+ desmos: {
199
+ degreeMode: true,
200
+ functionDefinition: true
201
+ }
202
+ }
203
+ );
204
+ ```
205
+
206
+ ### Graphing Calculator
207
+
208
+ ```typescript
209
+ const calculator = await provider.createCalculator(
210
+ 'graphing',
211
+ document.getElementById('calculator-container'),
212
+ {
213
+ desmos: {
214
+ expressions: true,
215
+ settingsMenu: true,
216
+ zoomButtons: true,
217
+ plotInequalities: true
218
+ }
219
+ }
220
+ );
221
+ ```
222
+
223
+ ### Restricted/Test Mode
224
+
225
+ For assessments, you can restrict calculator features:
226
+
227
+ ```typescript
228
+ const calculator = await provider.createCalculator(
229
+ 'graphing',
230
+ container,
231
+ {
232
+ restrictedMode: true, // Disables settings, zoom, expressions topbar
233
+ desmos: {
234
+ restrictedFunctions: true // Additional Desmos restrictions
235
+ }
236
+ }
237
+ );
238
+ ```
239
+
240
+ ## Configuration Options
241
+
242
+ See the `DesmosCalculatorConfig` interface in `@pie-players/pie-calculator` for all available options.
243
+
244
+ Common options:
245
+
246
+ - `expressions`: Show/hide expression list (graphing)
247
+ - `settingsMenu`: Show/hide settings menu
248
+ - `zoomButtons`: Show/hide zoom controls
249
+ - `degreeMode`: Use degrees instead of radians
250
+ - `border`: Show calculator border
251
+ - `links`: Enable links to Desmos.com
252
+
253
+ ## State Management
254
+
255
+ Save and restore calculator state:
256
+
257
+ ```typescript
258
+ // Export state
259
+ const state = calculator.exportState();
260
+ localStorage.setItem('calculator-state', JSON.stringify(state));
261
+
262
+ // Import state
263
+ const savedState = JSON.parse(localStorage.getItem('calculator-state'));
264
+ calculator.importState(savedState);
265
+ ```
266
+
267
+ ## Loading Desmos API
268
+
269
+ The Desmos API must be loaded before initializing the provider. You can load it from CDN:
270
+
271
+ ```html
272
+ <script src="https://www.desmos.com/api/v1.10/calculator.js?apiKey=REDACTED_API_KEY"></script>
273
+ ```
274
+
275
+ Or load it dynamically in your application.
276
+
277
+ ## License
278
+
279
+ This package is MIT licensed. The Desmos API requires a separate API key from Desmos.
280
+
281
+ ## Links
282
+
283
+ - [Desmos API Documentation](https://www.desmos.com/api)
284
+ - [Get Desmos API Key](https://www.desmos.com/api)
285
+ - [PIE Calculator Base Package](https://www.npmjs.com/package/@pie-players/pie-calculator)
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Desmos Calculator Provider
3
+ * Implementation of CalculatorProvider for Desmos calculators
4
+ *
5
+ * Supports: Basic, Scientific, and Graphing calculators
6
+ * Based on Desmos API v1.10+
7
+ * Requires: Desmos API key (obtain from https://www.desmos.com/api)
8
+ *
9
+ * SECURITY BEST PRACTICE:
10
+ * - Development: Pass apiKey directly for local testing
11
+ * - Production: Use proxyEndpoint to keep API key server-side
12
+ *
13
+ * Example server-side proxy (Express.js):
14
+ * ```
15
+ * app.get('/api/desmos/token', requireAuth, (req, res) => {
16
+ * res.json({ apiKey: process.env.DESMOS_API_KEY });
17
+ * });
18
+ * ```
19
+ */
20
+ import type { Calculator, CalculatorProvider, CalculatorProviderCapabilities, CalculatorProviderConfig, CalculatorType } from "@pie-players/pie-calculator";
21
+ declare global {
22
+ interface Window {
23
+ Desmos?: any;
24
+ }
25
+ }
26
+ /**
27
+ * Desmos Calculator Provider Implementation
28
+ */
29
+ export declare class DesmosCalculatorProvider implements CalculatorProvider {
30
+ readonly providerId = "desmos";
31
+ readonly providerName = "Desmos";
32
+ readonly supportedTypes: CalculatorType[];
33
+ readonly version = "1.10";
34
+ private initialized;
35
+ private apiKey?;
36
+ private proxyEndpoint?;
37
+ private isDevelopment;
38
+ /**
39
+ * Get the configured API key
40
+ * @internal Used internally by calculator instances
41
+ */
42
+ getApiKey(): string | undefined;
43
+ /**
44
+ * Dynamically load the Desmos calculator library
45
+ * @private
46
+ */
47
+ private loadDesmosScript;
48
+ /**
49
+ * Initialize Desmos library
50
+ * @param config Configuration with API key (development) or proxy endpoint (production)
51
+ */
52
+ initialize(config?: {
53
+ apiKey?: string;
54
+ proxyEndpoint?: string;
55
+ }): Promise<void>;
56
+ /**
57
+ * Create a calculator instance
58
+ */
59
+ createCalculator(type: CalculatorType, container: HTMLElement, config?: CalculatorProviderConfig): Promise<Calculator>;
60
+ /**
61
+ * Check if type is supported
62
+ */
63
+ supportsType(type: CalculatorType): boolean;
64
+ /**
65
+ * Cleanup
66
+ */
67
+ destroy(): void;
68
+ /**
69
+ * Get provider capabilities
70
+ */
71
+ getCapabilities(): CalculatorProviderCapabilities;
72
+ }
73
+ //# sourceMappingURL=desmos-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"desmos-provider.d.ts","sourceRoot":"","sources":["../src/desmos-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EACX,UAAU,EACV,kBAAkB,EAClB,8BAA8B,EAC9B,wBAAwB,EAExB,cAAc,EAEd,MAAM,6BAA6B,CAAC;AAErC,OAAO,CAAC,MAAM,CAAC;IACd,UAAU,MAAM;QACf,MAAM,CAAC,EAAE,GAAG,CAAC;KACb;CACD;AAED;;GAEG;AACH,qBAAa,wBAAyB,YAAW,kBAAkB;IAClE,QAAQ,CAAC,UAAU,YAAY;IAC/B,QAAQ,CAAC,YAAY,YAAY;IACjC,QAAQ,CAAC,cAAc,EAAE,cAAc,EAAE,CAIvC;IACF,QAAQ,CAAC,OAAO,UAAU;IAE1B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,MAAM,CAAC,CAAS;IACxB,OAAO,CAAC,aAAa,CAAC,CAAS;IAC/B,OAAO,CAAC,aAAa,CAAS;IAE9B;;;OAGG;IACH,SAAS,IAAI,MAAM,GAAG,SAAS;IAI/B;;;OAGG;YACW,gBAAgB;IAwB9B;;;OAGG;IACG,UAAU,CAAC,MAAM,CAAC,EAAE;QACzB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,aAAa,CAAC,EAAE,MAAM,CAAC;KACvB,GAAG,OAAO,CAAC,IAAI,CAAC;IAqEjB;;OAEG;IACG,gBAAgB,CACrB,IAAI,EAAE,cAAc,EACpB,SAAS,EAAE,WAAW,EACtB,MAAM,CAAC,EAAE,wBAAwB,GAC/B,OAAO,CAAC,UAAU,CAAC;IAYtB;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO;IAI3C;;OAEG;IACH,OAAO,IAAI,IAAI;IAIf;;OAEG;IACH,eAAe,IAAI,8BAA8B;CAUjD"}
@@ -0,0 +1,301 @@
1
+ /**
2
+ * Desmos Calculator Provider
3
+ * Implementation of CalculatorProvider for Desmos calculators
4
+ *
5
+ * Supports: Basic, Scientific, and Graphing calculators
6
+ * Based on Desmos API v1.10+
7
+ * Requires: Desmos API key (obtain from https://www.desmos.com/api)
8
+ *
9
+ * SECURITY BEST PRACTICE:
10
+ * - Development: Pass apiKey directly for local testing
11
+ * - Production: Use proxyEndpoint to keep API key server-side
12
+ *
13
+ * Example server-side proxy (Express.js):
14
+ * ```
15
+ * app.get('/api/desmos/token', requireAuth, (req, res) => {
16
+ * res.json({ apiKey: process.env.DESMOS_API_KEY });
17
+ * });
18
+ * ```
19
+ */
20
+ /**
21
+ * Desmos Calculator Provider Implementation
22
+ */
23
+ export class DesmosCalculatorProvider {
24
+ providerId = "desmos";
25
+ providerName = "Desmos";
26
+ supportedTypes = [
27
+ "basic",
28
+ "scientific",
29
+ "graphing",
30
+ ];
31
+ version = "1.10";
32
+ initialized = false;
33
+ apiKey;
34
+ proxyEndpoint;
35
+ isDevelopment = false;
36
+ /**
37
+ * Get the configured API key
38
+ * @internal Used internally by calculator instances
39
+ */
40
+ getApiKey() {
41
+ return this.apiKey;
42
+ }
43
+ /**
44
+ * Dynamically load the Desmos calculator library
45
+ * @private
46
+ */
47
+ async loadDesmosScript() {
48
+ return new Promise((resolve, reject) => {
49
+ const script = document.createElement("script");
50
+ // Include API key in script URL if available
51
+ const scriptUrl = this.apiKey
52
+ ? `https://www.desmos.com/api/v1.10/calculator.js?apiKey=${this.apiKey}`
53
+ : "https://www.desmos.com/api/v1.10/calculator.js";
54
+ script.src = scriptUrl;
55
+ script.async = true;
56
+ script.onload = () => {
57
+ if (window.Desmos) {
58
+ console.log("[DesmosProvider] Desmos API loaded successfully");
59
+ resolve();
60
+ }
61
+ else {
62
+ reject(new Error("Desmos API loaded but window.Desmos is undefined"));
63
+ }
64
+ };
65
+ script.onerror = () => {
66
+ reject(new Error("Failed to load Desmos API from CDN"));
67
+ };
68
+ document.head.appendChild(script);
69
+ });
70
+ }
71
+ /**
72
+ * Initialize Desmos library
73
+ * @param config Configuration with API key (development) or proxy endpoint (production)
74
+ */
75
+ async initialize(config) {
76
+ if (this.initialized)
77
+ return;
78
+ // SSR guard
79
+ if (typeof window === "undefined") {
80
+ throw new Error("Desmos calculators can only be initialized in the browser");
81
+ }
82
+ // Determine if we're in development mode
83
+ this.isDevelopment =
84
+ process.env.NODE_ENV === "development" ||
85
+ typeof process === "undefined" ||
86
+ !process.env.NODE_ENV;
87
+ // Configure API access pattern
88
+ if (config?.proxyEndpoint) {
89
+ // Production pattern: server-side proxy
90
+ this.proxyEndpoint = config.proxyEndpoint;
91
+ try {
92
+ const response = await fetch(config.proxyEndpoint);
93
+ if (!response.ok) {
94
+ throw new Error(`Proxy endpoint returned ${response.status}`);
95
+ }
96
+ const data = await response.json();
97
+ this.apiKey = data.apiKey;
98
+ console.log("[DesmosProvider] Initialized with server-side proxy (SECURE)");
99
+ }
100
+ catch (error) {
101
+ throw new Error(`[DesmosProvider] Failed to fetch API key from proxy: ${error}`);
102
+ }
103
+ }
104
+ else if (config?.apiKey) {
105
+ // Development pattern: direct API key
106
+ this.apiKey = config.apiKey;
107
+ // Security warning in production
108
+ if (!this.isDevelopment) {
109
+ console.error("⚠️ [DesmosProvider] SECURITY WARNING: API key exposed in client-side code!\n" +
110
+ "This is insecure for production. Use proxyEndpoint instead.\n" +
111
+ "See: https://pie-players.dev/docs/calculator-desmos#security");
112
+ }
113
+ else {
114
+ console.log("[DesmosProvider] Initialized with direct API key (DEVELOPMENT MODE)");
115
+ }
116
+ }
117
+ else {
118
+ // No API key provided
119
+ console.warn("[DesmosProvider] No API key or proxy endpoint provided.\n" +
120
+ "Production usage requires authentication. Obtain API key from https://www.desmos.com/api\n" +
121
+ "Recommended: Use proxyEndpoint for production, apiKey for development only.");
122
+ }
123
+ // Load Desmos API if not already loaded
124
+ if (!window.Desmos) {
125
+ console.log("[DesmosProvider] Loading Desmos API library...");
126
+ await this.loadDesmosScript();
127
+ }
128
+ this.initialized = true;
129
+ }
130
+ /**
131
+ * Create a calculator instance
132
+ */
133
+ async createCalculator(type, container, config) {
134
+ if (!this.initialized) {
135
+ await this.initialize();
136
+ }
137
+ if (!this.supportsType(type)) {
138
+ throw new Error(`Desmos does not support calculator type: ${type}`);
139
+ }
140
+ return new DesmosCalculator(this, type, container, config, this.apiKey);
141
+ }
142
+ /**
143
+ * Check if type is supported
144
+ */
145
+ supportsType(type) {
146
+ return this.supportedTypes.includes(type);
147
+ }
148
+ /**
149
+ * Cleanup
150
+ */
151
+ destroy() {
152
+ this.initialized = false;
153
+ }
154
+ /**
155
+ * Get provider capabilities
156
+ */
157
+ getCapabilities() {
158
+ return {
159
+ supportsHistory: false, // Desmos doesn't expose history API
160
+ supportsGraphing: true,
161
+ supportsExpressions: true,
162
+ canExport: true,
163
+ maxPrecision: 15,
164
+ inputMethods: ["keyboard", "mouse", "touch"],
165
+ };
166
+ }
167
+ }
168
+ /**
169
+ * Desmos Calculator Instance
170
+ */
171
+ class DesmosCalculator {
172
+ provider;
173
+ type;
174
+ Desmos;
175
+ calculator;
176
+ container;
177
+ constructor(provider, type, container, config, apiKey) {
178
+ this.provider = provider;
179
+ this.type = type;
180
+ this.container = container;
181
+ this.Desmos = window.Desmos;
182
+ if (!this.Desmos) {
183
+ throw new Error("Desmos API not available");
184
+ }
185
+ this._initializeCalculator(config, apiKey);
186
+ }
187
+ _initializeCalculator(config, apiKey) {
188
+ // Merge Desmos-specific config with defaults
189
+ const desmosConfig = {
190
+ ...(config?.desmos || {}),
191
+ apiKey: apiKey || config?.desmos?.apiKey,
192
+ };
193
+ // Apply restricted mode if specified
194
+ if (config?.restrictedMode) {
195
+ Object.assign(desmosConfig, {
196
+ expressionsTopbar: false,
197
+ settingsMenu: false,
198
+ zoomButtons: false,
199
+ expressions: false,
200
+ links: false,
201
+ });
202
+ }
203
+ // Create appropriate calculator type
204
+ switch (this.type) {
205
+ case "graphing":
206
+ this.calculator = this.Desmos.GraphingCalculator(this.container, desmosConfig);
207
+ break;
208
+ case "scientific":
209
+ this.calculator = this.Desmos.ScientificCalculator(this.container, desmosConfig);
210
+ break;
211
+ case "basic":
212
+ this.calculator = this.Desmos.FourFunctionCalculator(this.container, desmosConfig);
213
+ break;
214
+ default:
215
+ throw new Error(`Unsupported calculator type: ${this.type}`);
216
+ }
217
+ console.log(`[DesmosCalculator] Created ${this.type} calculator`);
218
+ }
219
+ getValue() {
220
+ // For graphing calculator, get the state
221
+ if (this.type === "graphing" && this.calculator.getState) {
222
+ const state = this.calculator.getState();
223
+ return JSON.stringify(state);
224
+ }
225
+ // For other calculators, return empty (Desmos doesn't expose value API)
226
+ return "";
227
+ }
228
+ setValue(value) {
229
+ // For graphing calculator, set the state
230
+ if (this.type === "graphing" && this.calculator.setState) {
231
+ try {
232
+ const state = JSON.parse(value);
233
+ this.calculator.setState(state);
234
+ }
235
+ catch (error) {
236
+ console.error("[DesmosCalculator] Failed to set state:", error);
237
+ }
238
+ }
239
+ }
240
+ clear() {
241
+ if (this.calculator.setBlank) {
242
+ this.calculator.setBlank();
243
+ }
244
+ }
245
+ async evaluate(expression) {
246
+ // Desmos doesn't provide a direct evaluate API
247
+ // For graphing calculator, add expression and observe
248
+ if (this.type === "graphing") {
249
+ return new Promise((resolve) => {
250
+ const id = `eval_${Date.now()}`;
251
+ this.calculator.setExpression({ id, latex: expression });
252
+ // Give Desmos time to process
253
+ setTimeout(() => {
254
+ const helperExpression = this.calculator.HelperExpression({
255
+ latex: expression,
256
+ });
257
+ const result = helperExpression.numericValue || expression;
258
+ this.calculator.removeExpression({ id });
259
+ resolve(String(result));
260
+ }, 100);
261
+ });
262
+ }
263
+ return expression;
264
+ }
265
+ resize() {
266
+ if (this.calculator.resize) {
267
+ this.calculator.resize();
268
+ }
269
+ }
270
+ exportState() {
271
+ let providerState = {};
272
+ if (this.type === "graphing" && this.calculator.getState) {
273
+ providerState = this.calculator.getState();
274
+ }
275
+ return {
276
+ type: this.type,
277
+ provider: "desmos",
278
+ value: this.getValue(),
279
+ providerState,
280
+ };
281
+ }
282
+ importState(state) {
283
+ if (state.provider !== "desmos") {
284
+ throw new Error(`Cannot import state from provider: ${state.provider}`);
285
+ }
286
+ if (state.providerState && this.calculator.setState) {
287
+ this.calculator.setState(state.providerState);
288
+ }
289
+ else if (state.value) {
290
+ this.setValue(state.value);
291
+ }
292
+ }
293
+ destroy() {
294
+ if (this.calculator && this.calculator.destroy) {
295
+ this.calculator.destroy();
296
+ }
297
+ this.container.replaceChildren();
298
+ console.log("[DesmosCalculator] destroyed");
299
+ }
300
+ }
301
+ //# sourceMappingURL=desmos-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"desmos-provider.js","sourceRoot":"","sources":["../src/desmos-provider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @pie-players/pie-calculator-desmos
3
+ *
4
+ * Desmos calculator provider - High-quality graphing calculators.
5
+ */
6
+ export { DesmosCalculatorProvider } from "./desmos-provider";
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @pie-players/pie-calculator-desmos
3
+ *
4
+ * Desmos calculator provider - High-quality graphing calculators.
5
+ */
6
+ export { DesmosCalculatorProvider } from "./desmos-provider";
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC"}
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@pie-players/pie-calculator-desmos",
3
+ "version": "0.1.2",
4
+ "description": "Desmos calculator provider for PIE Assessment Toolkit - High-quality graphing calculators",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "README.md"
17
+ ],
18
+ "scripts": {
19
+ "build": "tsc",
20
+ "typecheck": "tsc --noEmit"
21
+ },
22
+ "keywords": [
23
+ "pie",
24
+ "calculator",
25
+ "desmos",
26
+ "graphing",
27
+ "math",
28
+ "accessibility"
29
+ ],
30
+ "author": "PIE Framework",
31
+ "license": "MIT",
32
+ "publishConfig": {
33
+ "access": "public"
34
+ },
35
+ "dependencies": {
36
+ "@pie-players/pie-calculator": "0.1.1"
37
+ },
38
+ "devDependencies": {
39
+ "typescript": "^5.7.2"
40
+ }
41
+ }