scratchblocks-plus 1.0.2 → 1.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.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * scratchblocks-plus v1.0.2
2
+ * scratchblocks-plus v1.1.0
3
3
  * https://luyifei2011.github.io/scratchblocks-plus
4
4
  * Make pictures of Scratch blocks from text.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * scratchblocks-plus v1.0.2
2
+ * scratchblocks-plus v1.1.0
3
3
  * https://luyifei2011.github.io/scratchblocks-plus
4
4
  * Make pictures of Scratch blocks from text.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * scratchblocks-plus v1.0.2
2
+ * scratchblocks-plus v1.1.0
3
3
  * https://luyifei2011.github.io/scratchblocks-plus
4
4
  * Make pictures of Scratch blocks from text.
5
5
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- * scratchblocks-plus v1.0.2
2
+ * scratchblocks-plus v1.1.0
3
3
  * https://luyifei2011.github.io/scratchblocks-plus
4
4
  * Make pictures of Scratch blocks from text.
5
5
  *
package/node-ssr.js ADDED
@@ -0,0 +1,81 @@
1
+ import init from "./index.js"
2
+ import { parse } from "./syntax/index.js"
3
+
4
+ let nodeWindow
5
+
6
+ try {
7
+ const { JSDOM } = await import("jsdom")
8
+ const dom = new JSDOM()
9
+ nodeWindow = dom.window
10
+ } catch {
11
+ try {
12
+ let createCanvas
13
+ const { DOMParser, XMLSerializer, DOMImplementation } =
14
+ await import("@xmldom/xmldom")
15
+ const nodeDocument = new DOMImplementation().createDocument(
16
+ "http://www.w3.org/2000/svg",
17
+ null,
18
+ null,
19
+ )
20
+ try {
21
+ createCanvas = (await import("@napi-rs/canvas")).createCanvas
22
+ } catch {
23
+ try {
24
+ createCanvas = (await import("canvas")).createCanvas
25
+ } catch {
26
+ // pass
27
+ }
28
+ }
29
+ if (createCanvas) {
30
+ const origCreateElement = nodeDocument.createElement.bind(nodeDocument)
31
+ nodeDocument.createElement = tagName =>
32
+ tagName === "canvas"
33
+ ? createCanvas(300, 150)
34
+ : origCreateElement(tagName)
35
+ }
36
+ nodeWindow = {
37
+ document: nodeDocument,
38
+ DOMParser,
39
+ XMLSerializer,
40
+ }
41
+ } catch {
42
+ // pass
43
+ }
44
+ }
45
+
46
+ const sb = init(nodeWindow)
47
+
48
+ export const {
49
+ allLanguages,
50
+ loadLanguages,
51
+ Label,
52
+ Icon,
53
+ Input,
54
+ Block,
55
+ Comment,
56
+ Script,
57
+ Document,
58
+ newView,
59
+ render,
60
+ } = sb
61
+
62
+ export { parse }
63
+
64
+ /**
65
+ * Parse Scratch block code and render it directly to an SVG XML string.
66
+ *
67
+ * @param {string} code - Scratch block source, e.g. "move (10) steps"
68
+ * @param {object} [options] - Same options accepted by scratchblocks.render()
69
+ * - style: "scratch3" | "scratch3-high-contrast" | "scratch2" (default: "scratch3")
70
+ * - languages: string[] (default: ["en"])
71
+ * - scale: number (default: 1)
72
+ * @returns {string} Complete SVG XML string
73
+ */
74
+ export function renderToSVGString(code, options = {}) {
75
+ options = { style: "scratch3", ...options }
76
+ const doc = parse(code, options)
77
+ const view = sb.newView(doc, options)
78
+ const svg = view.render()
79
+ svg.setAttribute("class", `scratchblocks-style-${options.style}`)
80
+ return view.exportSVGString()
81
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "scratchblocks-plus",
3
- "version": "1.0.2",
3
+ "version": "1.1.0",
4
4
  "description": "Make pictures of Scratch blocks from text.",
5
5
  "license": "MIT",
6
6
  "author": "Lu Yifei",
@@ -21,7 +21,7 @@
21
21
  },
22
22
  "scripts": {
23
23
  "build": "rollup -c --environment buildTarget:PROD",
24
- "fmt": "prettier --cache --write *.js syntax/*.js scratch2/*.js scratch3/*.js locales-src/*.js snapshots/*.js snapshots/*.html tests/*.js",
24
+ "fmt": "prettier --cache --write *.js syntax/*.js scratch2/*.js scratch3/*.js locales-src/*.js snapshots/*.js tests/*.js",
25
25
  "lint:staged": "lint-staged",
26
26
  "lint": "eslint *.js syntax/*.js scratch2/*.js scratch3/*.js locales-src/*.js snapshots/*.js tests/*.js",
27
27
  "locales": "node locales-src/build-locales.js",
@@ -37,25 +37,46 @@
37
37
  "@babel/plugin-external-helpers": "^7.27.1",
38
38
  "@babel/preset-env": "^7.28.5",
39
39
  "@eslint/js": "^9.39.1",
40
+ "@napi-rs/canvas": "^0.1.96",
41
+ "@resvg/resvg-js": "^2.6.2",
40
42
  "@rollup/plugin-babel": "^6.1.0",
41
43
  "@rollup/plugin-json": "^6.1.0",
42
44
  "@rollup/plugin-terser": "^0.4.4",
45
+ "@xmldom/xmldom": "^0.8.11",
43
46
  "cross-env": "^10.1.0",
44
47
  "csso": "^5.0.5",
45
48
  "eslint": "^9.39.1",
46
- "express": "^5.1.0",
47
49
  "globals": "^16.5.0",
48
50
  "jest": "^30.2.0",
49
51
  "lint-staged": "^16.2.6",
50
52
  "prettier": "^3.6.2",
51
53
  "prettier-package-json": "^2.8.0",
52
- "puppeteer": "^24.30.0",
53
54
  "rollup": "^4.53.2",
54
55
  "rollup-plugin-license": "^3.6.0",
55
56
  "rollup-plugin-serve": "^3.0.0",
56
57
  "scratch-l10n": "^6.1.23",
57
58
  "scratch-translate-extension-languages": "^1.0.7"
58
59
  },
60
+ "peerDependencies": {
61
+ "@napi-rs/canvas": "*",
62
+ "@xmldom/xmldom": ">=0.8.0",
63
+ "canvas": ">=2.0.0",
64
+ "jsdom": ">=16.0.0"
65
+ },
66
+ "peerDependenciesMeta": {
67
+ "@xmldom/xmldom": {
68
+ "optional": true
69
+ },
70
+ "canvas": {
71
+ "optional": true
72
+ },
73
+ "@napi-rs/canvas": {
74
+ "optional": true
75
+ },
76
+ "jsdom": {
77
+ "optional": true
78
+ }
79
+ },
59
80
  "keywords": [
60
81
  "scratch"
61
82
  ],
@@ -22,6 +22,34 @@ const {
22
22
  iconName,
23
23
  } = style
24
24
 
25
+ // to be compatible with node.js xmldom
26
+ function addClass(el, className) {
27
+ if (el.classList) {
28
+ el.classList.add(className)
29
+ } else {
30
+ const current = el.getAttribute("class") || ""
31
+ const classes = current.split(/\s+/).filter(Boolean)
32
+ if (!classes.includes(className)) {
33
+ classes.push(className)
34
+ el.setAttribute("class", classes.join(" "))
35
+ }
36
+ }
37
+ }
38
+
39
+ function removeClass(el, className) {
40
+ if (el.classList) {
41
+ el.classList.remove(className)
42
+ } else {
43
+ const current = el.getAttribute("class") || ""
44
+ const classes = current.split(/\s+/).filter(cls => cls !== className)
45
+ if (classes.length) {
46
+ el.setAttribute("class", classes.join(" "))
47
+ } else {
48
+ el.removeAttribute("class")
49
+ }
50
+ }
51
+ }
52
+
25
53
  export class LabelView {
26
54
  constructor(label) {
27
55
  Object.assign(this, label)
@@ -329,7 +357,7 @@ export class InputView {
329
357
  })
330
358
  }
331
359
  } else if (this.shape === "number-dropdown") {
332
- el.classList.add(`sb3-${parent.info.category}-alt`)
360
+ addClass(el, `sb3-${parent.info.category}-alt`)
333
361
 
334
362
  // custom colors
335
363
  if (parent.info.color) {
@@ -339,8 +367,8 @@ export class InputView {
339
367
  })
340
368
  }
341
369
  } else if (this.shape === "boolean") {
342
- el.classList.remove(`sb3-${parent.info.category}`)
343
- el.classList.add(`sb3-${parent.info.category}-dark`)
370
+ removeClass(el, `sb3-${parent.info.category}`)
371
+ addClass(el, `sb3-${parent.info.category}-dark`)
344
372
 
345
373
  // custom colors
346
374
  if (parent.info.color) {
@@ -2,7 +2,9 @@
2
2
 
3
3
  const common = `
4
4
  .sb3-label {
5
- font: 500 12pt Helvetica Neue, Helvetica, sans-serif;
5
+ font-weight: 500;
6
+ font-size: 12pt;
7
+ font-family: Helvetica Neue, Helvetica, sans-serif;
6
8
  }
7
9
 
8
10
  .sb3-literal-number,
@@ -63,7 +65,9 @@ const commonOverride = `
63
65
  }
64
66
  /* specificity */
65
67
  .sb3-comment-label, .sb3-label.sb3-comment-label {
66
- font: 400 12pt Helvetica Neue, Helvetica, sans-serif;
68
+ font-weight: 400;
69
+ font-size: 12pt;
70
+ font-family: Helvetica Neue, Helvetica, sans-serif;
67
71
  fill: #000;
68
72
  word-spacing: 0;
69
73
  }`