@edadma/logo 0.2.2 → 0.2.4

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/package.json CHANGED
@@ -1,29 +1,22 @@
1
1
  {
2
2
  "name": "@edadma/logo",
3
- "version": "0.2.2",
4
- "description": "Logo programming language interpreter with React component",
3
+ "version": "0.2.4",
4
+ "description": "Logo programming language interpreter",
5
5
  "main": "dist/main.js",
6
6
  "module": "dist/main.js",
7
7
  "types": "src/index.d.ts",
8
8
  "files": [
9
9
  "dist",
10
- "src",
11
- "react"
10
+ "src"
12
11
  ],
13
12
  "exports": {
14
13
  ".": {
15
14
  "import": "./dist/main.js",
16
15
  "types": "./src/index.d.ts"
17
- },
18
- "./react": {
19
- "import": "./react/index.ts",
20
- "types": "./react/index.ts"
21
16
  }
22
17
  },
23
18
  "scripts": {
24
- "build": "npm run build:scala && npm run build:react",
25
- "build:scala": "cd .. && sbt logoJS/fullLinkJS && cp js/target/scala-3.7.4/logo-opt/main.js js/target/scala-3.7.4/logo-opt/main.js.map js/dist/",
26
- "build:react": "tsc --project tsconfig.react.json",
19
+ "build": "cd .. && sbt logoJS/fullLinkJS && cp js/target/scala-3.7.4/logo-opt/main.js js/target/scala-3.7.4/logo-opt/main.js.map js/dist/",
27
20
  "prepublishOnly": "npm run build"
28
21
  },
29
22
  "keywords": [
@@ -32,7 +25,6 @@
32
25
  "turtle",
33
26
  "graphics",
34
27
  "education",
35
- "react",
36
28
  "canvas"
37
29
  ],
38
30
  "author": "Edward A. Maxedon, Sr.",
@@ -44,17 +36,5 @@
44
36
  "bugs": {
45
37
  "url": "https://github.com/edadma/logo/issues"
46
38
  },
47
- "homepage": "https://github.com/edadma/logo#readme",
48
- "peerDependencies": {
49
- "react": ">=17.0.0"
50
- },
51
- "peerDependenciesMeta": {
52
- "react": {
53
- "optional": true
54
- }
55
- },
56
- "devDependencies": {
57
- "@types/react": "^18.2.0",
58
- "typescript": "^5.0.0"
59
- }
39
+ "homepage": "https://github.com/edadma/logo#readme"
60
40
  }
@@ -137,6 +137,12 @@ class LogoJS(canvas: html.Canvas) extends js.Object:
137
137
  def clearEventHandler(): Unit =
138
138
  eventHandler = None
139
139
 
140
+ /** Set a global variable */
141
+ def setVariable(name: String, value: Any): Unit = logo.setVariable(name, value)
142
+
143
+ /** Get a global variable */
144
+ def getVariable(name: String): Option[LogoValue] = logo.getVariable(name)
145
+
140
146
  /** Force a render */
141
147
  def render(): Unit =
142
148
  val width = canvas.width
@@ -306,22 +312,72 @@ class LogoJS(canvas: html.Canvas) extends js.Object:
306
312
  ctx.stroke()
307
313
 
308
314
  private def drawTurtle(x: Double, y: Double, heading: Double): Unit =
309
- val w = 15.0
310
- val h = 20.0
311
-
312
315
  ctx.save()
313
316
  ctx.translate(x, y)
314
- ctx.rotate(heading - Pi / 2)
317
+ ctx.rotate(heading + Pi / 2)
315
318
 
319
+ // Tail (behind shell)
316
320
  ctx.beginPath()
317
- ctx.moveTo(0, 0)
318
- ctx.lineTo(-w / 2, h / 2)
319
- ctx.lineTo(0, h)
320
- ctx.lineTo(w / 2, h / 2)
321
- ctx.closePath()
322
-
323
- ctx.strokeStyle = "green"
321
+ ctx.moveTo(0, 10)
322
+ ctx.lineTo(0, 14)
323
+ ctx.strokeStyle = "#4a7a44"
324
324
  ctx.lineWidth = 2
325
+ ctx.lineCap = "round"
326
+ ctx.stroke()
327
+
328
+ // Legs (behind shell)
329
+ ctx.fillStyle = "#4a7a44"
330
+ ctx.strokeStyle = "#1a3a18"
331
+ ctx.lineWidth = 1
332
+ // Front legs
333
+ ctx.beginPath()
334
+ ctx.ellipse(-7, -6, 3, 5, 0.4, 0, 2 * Pi)
335
+ ctx.fill()
336
+ ctx.stroke()
337
+ ctx.beginPath()
338
+ ctx.ellipse(7, -6, 3, 5, -0.4, 0, 2 * Pi)
339
+ ctx.fill()
340
+ ctx.stroke()
341
+ // Back legs
342
+ ctx.beginPath()
343
+ ctx.ellipse(-6, 6, 3, 4, 0.3, 0, 2 * Pi)
344
+ ctx.fill()
345
+ ctx.stroke()
346
+ ctx.beginPath()
347
+ ctx.ellipse(6, 6, 3, 4, -0.3, 0, 2 * Pi)
348
+ ctx.fill()
349
+ ctx.stroke()
350
+
351
+ // Head (behind shell)
352
+ ctx.beginPath()
353
+ ctx.ellipse(0, -14, 4, 5, 0, 0, 2 * Pi)
354
+ ctx.fillStyle = "#4a7a44"
355
+ ctx.fill()
356
+ ctx.strokeStyle = "#1a3a18"
357
+ ctx.lineWidth = 1.5
358
+ ctx.stroke()
359
+
360
+ // Eyes
361
+ ctx.fillStyle = "black"
362
+ ctx.beginPath()
363
+ ctx.arc(-1.5, -15, 1, 0, 2 * Pi)
364
+ ctx.arc(1.5, -15, 1, 0, 2 * Pi)
365
+ ctx.fill()
366
+
367
+ // Shell (on top)
368
+ ctx.beginPath()
369
+ ctx.ellipse(0, 0, 8, 10, 0, 0, 2 * Pi)
370
+ ctx.fillStyle = "#2d5a27"
371
+ ctx.fill()
372
+ ctx.strokeStyle = "#1a3a18"
373
+ ctx.lineWidth = 1.5
374
+ ctx.stroke()
375
+
376
+ // Shell pattern
377
+ ctx.strokeStyle = "#3d7a37"
378
+ ctx.lineWidth = 1
379
+ ctx.beginPath()
380
+ ctx.ellipse(0, 0, 5, 6, 0, 0, 2 * Pi)
325
381
  ctx.stroke()
326
382
 
327
383
  ctx.restore()
@@ -1,74 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { useRef, useEffect, useImperativeHandle, forwardRef } from 'react';
3
- export const LogoCanvas = forwardRef(({ width = 600, height = 400, program, pathRendering = true, onError, onComplete, className, style, }, ref) => {
4
- const canvasRef = useRef(null);
5
- const logoRef = useRef(null);
6
- // Initialize Logo instance
7
- useEffect(() => {
8
- if (canvasRef.current && typeof Logo !== 'undefined') {
9
- logoRef.current = new Logo(canvasRef.current);
10
- logoRef.current.setPathRendering(pathRendering);
11
- }
12
- }, []);
13
- // Update path rendering setting
14
- useEffect(() => {
15
- if (logoRef.current) {
16
- logoRef.current.setPathRendering(pathRendering);
17
- }
18
- }, [pathRendering]);
19
- // Run program when it changes
20
- useEffect(() => {
21
- if (logoRef.current && program !== undefined) {
22
- try {
23
- logoRef.current.clear();
24
- logoRef.current.run(program);
25
- onComplete?.();
26
- }
27
- catch (e) {
28
- onError?.(e instanceof Error ? e : new Error(String(e)));
29
- }
30
- }
31
- }, [program, onError, onComplete]);
32
- // Expose methods via ref
33
- useImperativeHandle(ref, () => ({
34
- execute: (command) => {
35
- if (logoRef.current) {
36
- try {
37
- logoRef.current.execute(command);
38
- }
39
- catch (e) {
40
- onError?.(e instanceof Error ? e : new Error(String(e)));
41
- }
42
- }
43
- },
44
- run: (prog) => {
45
- if (logoRef.current) {
46
- try {
47
- logoRef.current.run(prog);
48
- onComplete?.();
49
- }
50
- catch (e) {
51
- onError?.(e instanceof Error ? e : new Error(String(e)));
52
- }
53
- }
54
- },
55
- clear: () => {
56
- logoRef.current?.clear();
57
- },
58
- getDrawing: () => {
59
- return logoRef.current?.getDrawing() ?? { lines: [], labels: [] };
60
- },
61
- getTurtle: () => {
62
- return (logoRef.current?.getTurtle() ?? {
63
- x: 0,
64
- y: 0,
65
- heading: Math.PI / 2,
66
- visible: true,
67
- });
68
- },
69
- getLogo: () => logoRef.current,
70
- }));
71
- return (_jsx("canvas", { ref: canvasRef, width: width, height: height, className: className, style: { backgroundColor: 'white', ...style } }));
72
- });
73
- LogoCanvas.displayName = 'LogoCanvas';
74
- export default LogoCanvas;
@@ -1,2 +0,0 @@
1
- export { LogoCanvas } from './LogoCanvas';
2
- export { LogoCanvas as default } from './LogoCanvas';
@@ -1,174 +0,0 @@
1
- import React, { useRef, useEffect, useImperativeHandle, forwardRef } from 'react';
2
-
3
- // Type definitions for the Logo class from Scala.js
4
- interface LogoDrawing {
5
- lines: Array<{
6
- x1: number;
7
- y1: number;
8
- x2: number;
9
- y2: number;
10
- color: string;
11
- width: number;
12
- }>;
13
- labels: Array<{
14
- x: number;
15
- y: number;
16
- heading: number;
17
- text: string;
18
- }>;
19
- }
20
-
21
- interface TurtleState {
22
- x: number;
23
- y: number;
24
- heading: number;
25
- visible: boolean;
26
- }
27
-
28
- interface LogoInstance {
29
- run(program: string): void;
30
- execute(command: string): void;
31
- clear(): void;
32
- render(): void;
33
- setPathRendering(enabled: boolean): void;
34
- setAutoRender(enabled: boolean): void;
35
- getDrawing(): LogoDrawing;
36
- getTurtle(): TurtleState;
37
- }
38
-
39
- declare const Logo: new (canvas: HTMLCanvasElement) => LogoInstance;
40
-
41
- export interface LogoCanvasProps {
42
- /** Width of the canvas in pixels */
43
- width?: number;
44
- /** Height of the canvas in pixels */
45
- height?: number;
46
- /** Logo program to run */
47
- program?: string;
48
- /** Whether to use path-based rendering (smoother curves) */
49
- pathRendering?: boolean;
50
- /** Callback when an error occurs */
51
- onError?: (error: Error) => void;
52
- /** Callback when program execution completes */
53
- onComplete?: () => void;
54
- /** Additional CSS class for the canvas */
55
- className?: string;
56
- /** Additional inline styles for the canvas */
57
- style?: React.CSSProperties;
58
- }
59
-
60
- export interface LogoCanvasRef {
61
- /** Execute a Logo command */
62
- execute: (command: string) => void;
63
- /** Run a full Logo program */
64
- run: (program: string) => void;
65
- /** Clear the canvas and reset turtle */
66
- clear: () => void;
67
- /** Get the current drawing data */
68
- getDrawing: () => LogoDrawing;
69
- /** Get the current turtle state */
70
- getTurtle: () => TurtleState;
71
- /** Get the underlying Logo instance */
72
- getLogo: () => LogoInstance | null;
73
- }
74
-
75
- export const LogoCanvas = forwardRef<LogoCanvasRef, LogoCanvasProps>(
76
- (
77
- {
78
- width = 600,
79
- height = 400,
80
- program,
81
- pathRendering = true,
82
- onError,
83
- onComplete,
84
- className,
85
- style,
86
- },
87
- ref
88
- ) => {
89
- const canvasRef = useRef<HTMLCanvasElement>(null);
90
- const logoRef = useRef<LogoInstance | null>(null);
91
-
92
- // Initialize Logo instance
93
- useEffect(() => {
94
- if (canvasRef.current && typeof Logo !== 'undefined') {
95
- logoRef.current = new Logo(canvasRef.current);
96
- logoRef.current.setPathRendering(pathRendering);
97
- }
98
- }, []);
99
-
100
- // Update path rendering setting
101
- useEffect(() => {
102
- if (logoRef.current) {
103
- logoRef.current.setPathRendering(pathRendering);
104
- }
105
- }, [pathRendering]);
106
-
107
- // Run program when it changes
108
- useEffect(() => {
109
- if (logoRef.current && program !== undefined) {
110
- try {
111
- logoRef.current.clear();
112
- logoRef.current.run(program);
113
- onComplete?.();
114
- } catch (e) {
115
- onError?.(e instanceof Error ? e : new Error(String(e)));
116
- }
117
- }
118
- }, [program, onError, onComplete]);
119
-
120
- // Expose methods via ref
121
- useImperativeHandle(ref, () => ({
122
- execute: (command: string) => {
123
- if (logoRef.current) {
124
- try {
125
- logoRef.current.execute(command);
126
- } catch (e) {
127
- onError?.(e instanceof Error ? e : new Error(String(e)));
128
- }
129
- }
130
- },
131
- run: (prog: string) => {
132
- if (logoRef.current) {
133
- try {
134
- logoRef.current.run(prog);
135
- onComplete?.();
136
- } catch (e) {
137
- onError?.(e instanceof Error ? e : new Error(String(e)));
138
- }
139
- }
140
- },
141
- clear: () => {
142
- logoRef.current?.clear();
143
- },
144
- getDrawing: () => {
145
- return logoRef.current?.getDrawing() ?? { lines: [], labels: [] };
146
- },
147
- getTurtle: () => {
148
- return (
149
- logoRef.current?.getTurtle() ?? {
150
- x: 0,
151
- y: 0,
152
- heading: Math.PI / 2,
153
- visible: true,
154
- }
155
- );
156
- },
157
- getLogo: () => logoRef.current,
158
- }));
159
-
160
- return (
161
- <canvas
162
- ref={canvasRef}
163
- width={width}
164
- height={height}
165
- className={className}
166
- style={{ backgroundColor: 'white', ...style }}
167
- />
168
- );
169
- }
170
- );
171
-
172
- LogoCanvas.displayName = 'LogoCanvas';
173
-
174
- export default LogoCanvas;
package/react/index.ts DELETED
@@ -1,2 +0,0 @@
1
- export { LogoCanvas, type LogoCanvasProps, type LogoCanvasRef } from './LogoCanvas';
2
- export { LogoCanvas as default } from './LogoCanvas';