From 10cf68d7eca87f5749a5d8a3401ec48f04f20d8b Mon Sep 17 00:00:00 2001 From: Bob Pritchett <26860966+BobPritchett@users.noreply.github.com> Date: Mon, 30 Jun 2025 09:35:36 -0700 Subject: [PATCH 01/11] WIP: prep for upstream sync --- .vscode/launch.json | 14 + package.json | 3 +- site/config.js | 5 +- site/index.html | 33 +- site/index.js | 48 +- specifications/layout-system.md | 271 +++ src/paint-canvas.ts | 261 ++- src/paint-html.ts | 159 +- src/paint-svg.ts | 115 +- src/paint.ts | 1110 +++++++++-- src/parse-css.js | 3125 +++++++++++++++++++------------ src/parse-css.pegjs | 87 +- src/style.ts | 903 +++++---- test/paint-spy.js | 68 +- tsconfig.json | 11 +- 15 files changed, 4308 insertions(+), 1905 deletions(-) create mode 100644 .vscode/launch.json create mode 100644 specifications/layout-system.md diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..a7ff1c6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,14 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "msedge", + "request": "launch", + "name": "Open index.html", + "file": "d:\\code\\dropflow\\site\\index.html" + } + ] +} \ No newline at end of file diff --git a/package.json b/package.json index 15e243c..dac6d6a 100644 --- a/package.json +++ b/package.json @@ -2,8 +2,9 @@ "devDependencies": { "@codemirror/lang-html": "^6.4.8", "@codemirror/state": "^6.4.1", - "@ddietr/codemirror-themes": "^1.4.2", + "@ddietr/codemirror-themes": "^1.5.1", "@rollup/plugin-node-resolve": "^15.2.3", + "@types/codemirror": "^5.60.15", "@types/mocha": "^8.0.3", "@types/node": "^20.17.10", "canvas": "^3.1.0", diff --git a/site/config.js b/site/config.js index 1323853..655d0e2 100644 --- a/site/config.js +++ b/site/config.js @@ -2,12 +2,11 @@ import {environment} from 'dropflow/environment.js'; import wasmUrl from 'dropflow/dropflow.wasm?url'; environment.wasmLocator = function () { - return fetch(wasmUrl).then(res => { + return fetch(wasmUrl).then((res) => { if (res.status === 200) { - return res.arrayBuffer() + return res.arrayBuffer(); } else { throw new Error(res.statusText); } }); }; - diff --git a/site/index.html b/site/index.html index 5cec67b..7b32c5b 100644 --- a/site/index.html +++ b/site/index.html @@ -1,17 +1,34 @@ - +
+ playground
+ + To the left and right are examples of floats. + Floats are placed as they are encountered + in text, so text that comes after them won't collide with them. + If this text doesn't go underneath the floats, resize your browser window. +
+ + + +Light weight text (300)
+Regular weight text (400)
+Semi-bold weight text (600)
+Bold weight text (700)
+Italic text style
+❌ Underlined text
+❌ Strikethrough text
+Left aligned text
+Center aligned text
+Right aligned text
+Justified text that spreads across the full width of the container, creating even margins on both sides.
++ Here is some standard English (Left-to-Right) text to start. We can seamlessly embed Arabic, which is a Right-to-Left language: مرحبا بالعالم، كيف حالك اليوم؟. Notice how the text flows correctly. The sentence continues in English, and now we will add some Hebrew (also RTL): שלום עולם!. The layout respects the directionality of each script, even when they are mixed together. We can finish the paragraph with some Spanish (LTR): ¡Hola, Mundo! +
+ +Small text (0.8em)
+Normal text (1em)
+Large text (1.2em)
+Extra large text (1.5em)
+Text with increased line height for better readability
+Text with letter spacing
+Text with word spacing
+Mathematical symbols: α β γ δ ε ζ η θ ι κ λ μ ν ξ ο π ρ σ τ υ φ χ ψ ω
+Currency symbols: $ € £ ¥ ₹ ₿
+Arrows: ← → ↑ ↓ ↔ ↕ ⇐ ⇒ ⇑ ⇓ ⇔ ⇕
+Emojis: 🚀 💻 🎨 📱 🌟 ✨
+This is the first grid item with some sample content.
+Second grid item with different styling.
+Third grid item with green theme.
+Fourth item with orange accent.
+Fifth item with pink styling.
+Sixth and final grid item.
+This is the main content area that takes up more space in the grid. It demonstrates how CSS Grid can create flexible layouts with different column widths.
+The grid system allows for responsive design and easy maintenance of layout structure.
+This demonstrates auto-fit with minmax for responsive behavior.
+Items automatically adjust based on available space.
+Minimum 200px width, but can grow to fill space.
+This is the outer container with a dark border.
+ +This is a nested container with a dashed border.
+ +This is the innermost container with a thin border.
+Each side has a different border style: solid top, dashed right, double bottom, dotted left.
+Each corner has a different radius: 20px, 5px, 15px, 10px (clockwise from top-left).
+Light shadow for depth without being too prominent.
+More pronounced shadow for greater depth perception.
+
- playground
- - To the left and right are examples of floats. - Floats are placed as they are encountered - in text, so text that comes after them won't collide with them. - If this text doesn't go underneath the floats, resize your browser window. -
- - - -Light weight text (300)
-Regular weight text (400)
-Semi-bold weight text (600)
-Bold weight text (700)
-Italic text style
-❌ Underlined text
-❌ Strikethrough text
+Thin (100), Extra Light (200), Light (300), Regular (400), Medium (500), Semi-Bold (600), Bold (700), Extra Bold (800), Black (900)
+Italic text, Oblique text, Small Caps, All Small Caps
+Underlined text, Overlined text, Strikethrough text, and Underlined and Overlined text
+Dotted underlined text with offset, Dashed underlined text, Solid underlined, Double underlined text with offset, Wavy Underlined text with big offset
The API integrates seamlessly with our system.
+Execute the runProcess() function to start the task.
This feature was recently added to enhance performance.
+The old method was deprecated due to security issues.
Check the output.log file for debug information.
+Key updates are marked with Ctrl + S for quick saves.
+The userCount variable tracks active users.
+Small text (0.8em)
Normal text (1em)
Large text (1.2em)
Extra large text (1.5em)
-Text with increased line height for better readability
Text with letter spacing
Text with word spacing
-Mathematical symbols: α β γ δ ε ζ η θ ι κ λ μ ν ξ ο π ρ σ τ υ φ χ ψ ω
Currency symbols: $ € £ ¥ ₹ ₿
From 8df723d3eefe0f1b6a27ca225e745abcdcc1ab7f Mon Sep 17 00:00:00 2001 From: Bob Pritchett <26860966+BobPritchett@users.noreply.github.com> Date: Wed, 2 Jul 2025 17:54:06 -0700 Subject: [PATCH 08/11] Refactor border-radius parsing and handling - Updated the border-radius parsing rules to support both horizontal and vertical radius values, allowing for more flexible CSS definitions. - Introduced helper functions for expanding radius values and handling slash-separated radius lists. - Refactored related functions to improve clarity and maintainability, ensuring consistent handling of border radius properties across the codebase. --- src/parse-css.js | 366 +++++++++++++++++++------------------------- src/parse-css.pegjs | 74 +++++---- 2 files changed, 206 insertions(+), 234 deletions(-) diff --git a/src/parse-css.js b/src/parse-css.js index 90f7629..c09ccf9 100644 --- a/src/parse-css.js +++ b/src/parse-css.js @@ -1127,38 +1127,50 @@ function peg$parse(input, options) { var peg$f115 = function(r) { return {borderBottomLeftRadius: r}; }; - var peg$f116 = function(tl, tr, br, bl) { - return { - borderTopLeftRadius: tl, - borderTopRightRadius: tr, - borderBottomRightRadius: br, - borderBottomLeftRadius: bl - }; - }; - var peg$f117 = function(t, h, b) { - return { - borderTopLeftRadius: t, - borderTopRightRadius: h, - borderBottomRightRadius: b, - borderBottomLeftRadius: h - }; - }; - var peg$f118 = function(v, h) { + var peg$f116 = function(horiz, vert) { + // If "vert" is undefined then no "/" was present – vertical radii reuse horizontal ones + const hasSlash = vert !== null && vert !== undefined; + + const hVals = horiz; + const vVals = hasSlash ? vert : horiz; + + function expand(list) { + switch (list.length) { + case 1: return [list[0], list[0], list[0], list[0]]; + case 2: return [list[0], list[1], list[0], list[1]]; + case 3: return [list[0], list[1], list[2], list[1]]; + default: /* 4 or more – use first four */ return [list[0], list[1], list[2], list[3]]; + } + } + + const h = expand(hVals); + const v = expand(vVals); + + function make(idx) { + return hasSlash ? { horizontal: h[idx], vertical: v[idx] } : h[idx]; + } + return { - borderTopLeftRadius: v, - borderTopRightRadius: h, - borderBottomRightRadius: v, - borderBottomLeftRadius: h + borderTopLeftRadius: make(0), + borderTopRightRadius: make(1), + borderBottomRightRadius: make(2), + borderBottomLeftRadius: make(3) }; }; - var peg$f119 = function(r) { + var peg$f117 = function(d) { + // Global keywords expand to all four corners return { - borderTopLeftRadius: r, - borderTopRightRadius: r, - borderBottomRightRadius: r, - borderBottomLeftRadius: r + borderTopLeftRadius: d, + borderTopRightRadius: d, + borderBottomRightRadius: d, + borderBottomLeftRadius: d }; }; + var peg$f118 = function(first, rest) { + const values = [first].concat(rest ? rest.map(r => r[1]) : []); + return values.slice(0, 4); // ignore extras beyond 4 if present +}; + var peg$f119 = function(r) { return r; }; var peg$f120 = function(t, w, s, c) { const ret = {}; setTopRightBottomLeftOr(t, ret, 'border', 'Width', w, w, w, w); @@ -1180,14 +1192,14 @@ function peg$parse(input, options) { if (s) setTopRightBottomLeftOr(t, ret, 'border', 'Style', s, s, s, s); return ret; }; - var peg$f123 = function(t, c, w, s) { + var peg$f123 = function(t, c, s, w) { const ret = {}; - setTopRightBottomLeftOr(t, ret, 'border', 'Width', w, w, w, w); setTopRightBottomLeftOr(t, ret, 'border', 'Color', c, c, c, c); - if (s) setTopRightBottomLeftOr(t, ret, 'border', 'Style', s, s, s, s); + setTopRightBottomLeftOr(t, ret, 'border', 'Style', s, s, s, s); + if (w) setTopRightBottomLeftOr(t, ret, 'border', 'Width', w, w, w, w); return ret; }; - var peg$f124 = function(t, c, w) { + var peg$f124 = function(t, w) { return setTopRightBottomLeftOr(t, {}, 'border', 'Width', w, w, w, w); }; var peg$f125 = function(t, c) { @@ -8172,7 +8184,7 @@ function peg$parse(input, options) { } function peg$parseborder_radius_dec() { - var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11; + var s0, s1, s2, s3, s4, s5, s6, s7; s0 = peg$currPos; if (input.substr(peg$currPos, 13).toLowerCase() === peg$c138) { @@ -8203,7 +8215,7 @@ function peg$parse(input, options) { s4.push(s5); s5 = peg$parseS(); } - s5 = peg$parselength_side(); + s5 = peg$parseradius_list(); if (s5 !== peg$FAILED) { s6 = []; s7 = peg$parseS(); @@ -8211,38 +8223,12 @@ function peg$parse(input, options) { s6.push(s7); s7 = peg$parseS(); } - s7 = peg$parselength_side(); - if (s7 !== peg$FAILED) { - s8 = []; - s9 = peg$parseS(); - while (s9 !== peg$FAILED) { - s8.push(s9); - s9 = peg$parseS(); - } - s9 = peg$parselength_side(); - if (s9 !== peg$FAILED) { - s10 = []; - s11 = peg$parseS(); - while (s11 !== peg$FAILED) { - s10.push(s11); - s11 = peg$parseS(); - } - s11 = peg$parselength_side(); - if (s11 !== peg$FAILED) { - peg$savedPos = s0; - s0 = peg$f116(s5, s7, s9, s11); - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; + s7 = peg$parseslash_radius(); + if (s7 === peg$FAILED) { + s7 = null; } + peg$savedPos = s0; + s0 = peg$f116(s5, s7); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -8285,34 +8271,10 @@ function peg$parse(input, options) { s4.push(s5); s5 = peg$parseS(); } - s5 = peg$parselength_side(); + s5 = peg$parsedefault(); if (s5 !== peg$FAILED) { - s6 = []; - s7 = peg$parseS(); - while (s7 !== peg$FAILED) { - s6.push(s7); - s7 = peg$parseS(); - } - s7 = peg$parselength_side(); - if (s7 !== peg$FAILED) { - s8 = []; - s9 = peg$parseS(); - while (s9 !== peg$FAILED) { - s8.push(s9); - s9 = peg$parseS(); - } - s9 = peg$parselength_side(); - if (s9 !== peg$FAILED) { - peg$savedPos = s0; - s0 = peg$f117(s5, s7, s9); - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } + peg$savedPos = s0; + s0 = peg$f117(s5); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -8325,115 +8287,119 @@ function peg$parse(input, options) { peg$currPos = s0; s0 = peg$FAILED; } - if (s0 === peg$FAILED) { - s0 = peg$currPos; - if (input.substr(peg$currPos, 13).toLowerCase() === peg$c138) { - s1 = input.substr(peg$currPos, 13); - peg$currPos += 13; + } + + return s0; + } + + function peg$parseradius_value() { + var s0; + + s0 = peg$parselength_side(); + if (s0 === peg$FAILED) { + s0 = peg$parsedefault(); + } + + return s0; + } + + function peg$parseradius_list() { + var s0, s1, s2, s3, s4, s5; + + s0 = peg$currPos; + s1 = peg$parseradius_value(); + if (s1 !== peg$FAILED) { + s2 = []; + s3 = peg$currPos; + s4 = []; + s5 = peg$parseS(); + if (s5 !== peg$FAILED) { + while (s5 !== peg$FAILED) { + s4.push(s5); + s5 = peg$parseS(); + } + } else { + s4 = peg$FAILED; + } + if (s4 !== peg$FAILED) { + s5 = peg$parseradius_value(); + if (s5 !== peg$FAILED) { + s4 = [s4, s5]; + s3 = s4; } else { - s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e143); } + peg$currPos = s3; + s3 = peg$FAILED; } - if (s1 !== peg$FAILED) { - s2 = []; - s3 = peg$parseS(); - while (s3 !== peg$FAILED) { - s2.push(s3); - s3 = peg$parseS(); - } - if (input.charCodeAt(peg$currPos) === 58) { - s3 = peg$c1; - peg$currPos++; - } else { - s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e1); } - } - if (s3 !== peg$FAILED) { - s4 = []; + } else { + peg$currPos = s3; + s3 = peg$FAILED; + } + while (s3 !== peg$FAILED) { + s2.push(s3); + s3 = peg$currPos; + s4 = []; + s5 = peg$parseS(); + if (s5 !== peg$FAILED) { + while (s5 !== peg$FAILED) { + s4.push(s5); s5 = peg$parseS(); - while (s5 !== peg$FAILED) { - s4.push(s5); - s5 = peg$parseS(); - } - s5 = peg$parselength_side(); - if (s5 !== peg$FAILED) { - s6 = []; - s7 = peg$parseS(); - while (s7 !== peg$FAILED) { - s6.push(s7); - s7 = peg$parseS(); - } - s7 = peg$parselength_side(); - if (s7 !== peg$FAILED) { - peg$savedPos = s0; - s0 = peg$f118(s5, s7); - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; } } else { - peg$currPos = s0; - s0 = peg$FAILED; + s4 = peg$FAILED; } - if (s0 === peg$FAILED) { - s0 = peg$currPos; - if (input.substr(peg$currPos, 13).toLowerCase() === peg$c138) { - s1 = input.substr(peg$currPos, 13); - peg$currPos += 13; - } else { - s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e143); } - } - if (s1 !== peg$FAILED) { - s2 = []; - s3 = peg$parseS(); - while (s3 !== peg$FAILED) { - s2.push(s3); - s3 = peg$parseS(); - } - if (input.charCodeAt(peg$currPos) === 58) { - s3 = peg$c1; - peg$currPos++; - } else { - s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e1); } - } - if (s3 !== peg$FAILED) { - s4 = []; - s5 = peg$parseS(); - while (s5 !== peg$FAILED) { - s4.push(s5); - s5 = peg$parseS(); - } - s5 = peg$parselength_side(); - if (s5 === peg$FAILED) { - s5 = peg$parsedefault(); - } - if (s5 !== peg$FAILED) { - peg$savedPos = s0; - s0 = peg$f119(s5); - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } + if (s4 !== peg$FAILED) { + s5 = peg$parseradius_value(); + if (s5 !== peg$FAILED) { + s4 = [s4, s5]; + s3 = s4; } else { - peg$currPos = s0; - s0 = peg$FAILED; + peg$currPos = s3; + s3 = peg$FAILED; } + } else { + peg$currPos = s3; + s3 = peg$FAILED; } } + peg$savedPos = s0; + s0 = peg$f118(s1, s2); + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + + return s0; + } + + function peg$parseslash_radius() { + var s0, s1, s2, s3; + + s0 = peg$currPos; + if (input.charCodeAt(peg$currPos) === 47) { + s1 = peg$c2; + peg$currPos++; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e2); } + } + if (s1 !== peg$FAILED) { + s2 = []; + s3 = peg$parseS(); + while (s3 !== peg$FAILED) { + s2.push(s3); + s3 = peg$parseS(); + } + s3 = peg$parseradius_list(); + if (s3 !== peg$FAILED) { + peg$savedPos = s0; + s0 = peg$f119(s3); + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; } return s0; @@ -8740,7 +8706,7 @@ function peg$parse(input, options) { s7.push(s8); s8 = peg$parseS(); } - s8 = peg$parseLENGTH(); + s8 = peg$parseborder_style(); if (s8 !== peg$FAILED) { s9 = []; s10 = peg$parseS(); @@ -8748,7 +8714,7 @@ function peg$parse(input, options) { s9.push(s10); s10 = peg$parseS(); } - s10 = peg$parseborder_style(); + s10 = peg$parseLENGTH(); if (s10 === peg$FAILED) { s10 = null; } @@ -8804,7 +8770,7 @@ function peg$parse(input, options) { s5.push(s6); s6 = peg$parseS(); } - s6 = peg$parsecolor(); + s6 = peg$parseLENGTH(); if (s6 !== peg$FAILED) { s7 = []; s8 = peg$parseS(); @@ -8812,20 +8778,8 @@ function peg$parse(input, options) { s7.push(s8); s8 = peg$parseS(); } - s8 = peg$parseLENGTH(); - if (s8 !== peg$FAILED) { - s9 = []; - s10 = peg$parseS(); - while (s10 !== peg$FAILED) { - s9.push(s10); - s10 = peg$parseS(); - } - peg$savedPos = s0; - s0 = peg$f124(s2, s6, s8); - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } + peg$savedPos = s0; + s0 = peg$f124(s2, s6); } else { peg$currPos = s0; s0 = peg$FAILED; diff --git a/src/parse-css.pegjs b/src/parse-css.pegjs index c96f187..de4edcd 100644 --- a/src/parse-css.pegjs +++ b/src/parse-css.pegjs @@ -704,39 +704,57 @@ border_bottom_left_radius_dec } border_radius_dec - = 'border-radius'i S* ':' S* tl:length_side S* tr:length_side S* br:length_side S* bl:length_side { - return { - borderTopLeftRadius: tl, - borderTopRightRadius: tr, - borderBottomRightRadius: br, - borderBottomLeftRadius: bl - }; - } - / 'border-radius'i S* ':' S* t:length_side S* h:length_side S* b:length_side { - return { - borderTopLeftRadius: t, - borderTopRightRadius: h, - borderBottomRightRadius: b, - borderBottomLeftRadius: h - }; - } - / 'border-radius'i S* ':' S* v:length_side S* h:length_side { + = 'border-radius'i S* ':' S* horiz:radius_list S* vert:slash_radius? { + // If "vert" is undefined then no "/" was present – vertical radii reuse horizontal ones + const hasSlash = vert !== null && vert !== undefined; + + const hVals = horiz; + const vVals = hasSlash ? vert : horiz; + + function expand(list) { + switch (list.length) { + case 1: return [list[0], list[0], list[0], list[0]]; + case 2: return [list[0], list[1], list[0], list[1]]; + case 3: return [list[0], list[1], list[2], list[1]]; + default: /* 4 or more – use first four */ return [list[0], list[1], list[2], list[3]]; + } + } + + const h = expand(hVals); + const v = expand(vVals); + + function make(idx) { + return hasSlash ? { horizontal: h[idx], vertical: v[idx] } : h[idx]; + } + return { - borderTopLeftRadius: v, - borderTopRightRadius: h, - borderBottomRightRadius: v, - borderBottomLeftRadius: h + borderTopLeftRadius: make(0), + borderTopRightRadius: make(1), + borderBottomRightRadius: make(2), + borderBottomLeftRadius: make(3) }; } - / 'border-radius'i S* ':' S* r:(length_side / default) { + / 'border-radius'i S* ':' S* d:default { + // Global keywords expand to all four corners return { - borderTopLeftRadius: r, - borderTopRightRadius: r, - borderBottomRightRadius: r, - borderBottomLeftRadius: r + borderTopLeftRadius: d, + borderTopRightRadius: d, + borderBottomRightRadius: d, + borderBottomLeftRadius: d }; } +// Helper rules -------------------------------------------------------------- + +radius_value = length_side / default + +radius_list = first:radius_value rest:(S+ radius_value)* { + const values = [first].concat(rest ? rest.map(r => r[1]) : []); + return values.slice(0, 4); // ignore extras beyond 4 if present +} + +slash_radius = '/' S* r:radius_list { return r; } + border_s = '-top' / '-right' / '-bottom' / '-left' border_dec @@ -761,7 +779,7 @@ border_dec if (s) setTopRightBottomLeftOr(t, ret, 'border', 'Style', s, s, s, s); return ret; } - / 'border'i t:border_s? S* ':' S* c:color S* w:LENGTH S* s:border_style? { + / 'border'i t:border_s? S* ':' S* c:color S* w:LENGTH S* s:border_style? { const ret = {}; setTopRightBottomLeftOr(t, ret, 'border', 'Width', w, w, w, w); setTopRightBottomLeftOr(t, ret, 'border', 'Color', c, c, c, c); @@ -775,7 +793,7 @@ border_dec if (w) setTopRightBottomLeftOr(t, ret, 'border', 'Width', w, w, w, w); return ret; } - / 'border'i t:border_s? S* ':' S* s:border_style S* c:color S* w:LENGTH? { + / 'border'i t:border_s? S* ':' S* s:border_style S* c:color S* w:LENGTH? { const ret = {}; setTopRightBottomLeftOr(t, ret, 'border', 'Color', c, c, c, c); setTopRightBottomLeftOr(t, ret, 'border', 'Style', s, s, s, s); From f63d0a5363dd51f96db2dcec4db795499527c1cd Mon Sep 17 00:00:00 2001 From: Bob Pritchett <26860966+BobPritchett@users.noreply.github.com> Date: Thu, 25 Sep 2025 12:06:47 -0700 Subject: [PATCH 09/11] Update package-lock.json and refactor type imports - Bump version from 0.5.1 to 0.6.0 in package-lock.json. - Update @ddietr/codemirror-themes dependency to version 1.5.1. - Add @types/codemirror and @types/tern as new dev dependencies. - Change import statements in box-border.ts to use type imports for better clarity. - Remove unnecessary border radius object in paint.ts to streamline code. --- package-lock.json | 31 +++++++++++++++++++++++++++---- src/box-border.ts | 2 +- src/paint.ts | 4 ---- 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index d83157d..6d0b909 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,18 +1,19 @@ { "name": "dropflow", - "version": "0.5.1", + "version": "0.6.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "dropflow", - "version": "0.5.1", + "version": "0.6.0", "license": "MIT", "devDependencies": { "@codemirror/lang-html": "^6.4.8", "@codemirror/state": "^6.4.1", - "@ddietr/codemirror-themes": "^1.4.2", + "@ddietr/codemirror-themes": "^1.5.1", "@rollup/plugin-node-resolve": "^15.2.3", + "@types/codemirror": "^5.60.15", "@types/mocha": "^8.0.3", "@types/node": "^20.17.10", "canvas": "^3.1.0", @@ -145,7 +146,9 @@ } }, "node_modules/@ddietr/codemirror-themes": { - "version": "1.4.2", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@ddietr/codemirror-themes/-/codemirror-themes-1.5.2.tgz", + "integrity": "sha512-hynMyioOgFM5FHqGtFcaH3kFFluo9KD2sKpDc/l86oGryahZWaKbOv46d8oPAoCmbggMm8WP5m9b64ZzIrPTDA==", "dev": true, "license": "MIT", "dependencies": { @@ -984,6 +987,16 @@ "win32" ] }, + "node_modules/@types/codemirror": { + "version": "5.60.16", + "resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-5.60.16.tgz", + "integrity": "sha512-V/yHdamffSS075jit+fDxaOAmdP2liok8NSNJnAZfDJErzOheuygHZEhAJrfmk5TEyM32MhkZjwo/idX791yxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/tern": "*" + } + }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", @@ -1011,6 +1024,16 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/tern": { + "version": "0.23.9", + "resolved": "https://registry.npmjs.org/@types/tern/-/tern-0.23.9.tgz", + "integrity": "sha512-ypzHFE/wBzh+BlH6rrBgS5I/Z7RD21pGhZ2rltb/+ZrVM1awdZwjx7hE5XfuYgHWk9uvV5HLZN3SloevCAp3Bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, "node_modules/ansi-colors": { "version": "4.1.1", "dev": true, diff --git a/src/box-border.ts b/src/box-border.ts index f1ceecf..7fc3026 100644 --- a/src/box-border.ts +++ b/src/box-border.ts @@ -1,4 +1,4 @@ -import { Color, BorderStyle, BorderRadius } from "./style.js"; +import type { Color, BorderStyle, BorderRadius } from "./style.js"; // Border rendering constants diff --git a/src/paint.ts b/src/paint.ts index 78e87ed..1c6e3d6 100644 --- a/src/paint.ts +++ b/src/paint.ts @@ -192,10 +192,6 @@ function paintFormattingBoxBackground( style: style.borderBottomStyle, color: style.borderBottomColor, }, - }; - - // Get border radius values from the style - const borderRadii = { topLeft: box.style.getBorderTopLeftRadius(box), topRight: box.style.getBorderTopRightRadius(box), bottomRight: box.style.getBorderBottomRightRadius(box), From ecff7e2a0773db2a429bb87b7c4dfd26c81d2dad Mon Sep 17 00:00:00 2001 From: Bob Pritchett <26860966+BobPritchett@users.noreply.github.com> Date: Thu, 25 Sep 2025 13:56:57 -0700 Subject: [PATCH 10/11] Refactor border-radius percentage calculations in Style class - Updated the handling of percentage values for border-radius to calculate horizontal and vertical radii based on the box's border area, improving accuracy. - Simplified the resolveEm function to handle percentage units more effectively, ensuring consistent unit resolution across styles. --- src/style.ts | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/style.ts b/src/style.ts index ab33b80..529e656 100644 --- a/src/style.ts +++ b/src/style.ts @@ -749,7 +749,12 @@ export class Style { if ( typeof radius === "number" && radius > 0 ) { return { horizontal: radius, vertical: radius }; } else if ( typeof radius === "object" && "value" in radius && "unit" in radius && radius.unit === "%" ) { - return { horizontal: resolvePercent(box, radius.value), vertical: resolvePercent(box, radius.value) }; + // Percentages for border-radius: horizontal relative to box width, vertical relative to box height + const area = box.getBorderArea(); + return { + horizontal: (radius.value / 100) * area.width, + vertical: (radius.value / 100) * area.height, + }; } else if ( typeof radius === "object" && "value" in radius && "unit" in radius ) { // em and fixed length units // TODO: check if this is correct -- can we count on it being a number here? @@ -762,7 +767,8 @@ export class Style { h = radius.horizontal; } else if ( typeof radius.horizontal === "object" && "value" in radius.horizontal ) { if ( radius.horizontal.unit === "%" ) { - h = resolvePercent(box, radius.horizontal.value); + const area = box.getBorderArea(); + h = (radius.horizontal.value / 100) * area.width; } else { h = resolveEm(radius.horizontal.value, this.fontSize) as number; } @@ -771,7 +777,8 @@ export class Style { v = radius.vertical; } else if ( typeof radius.vertical === "object" && "value" in radius.vertical ) { if ( radius.vertical.unit === "%" ) { - v = resolvePercent(box, radius.vertical.value); + const area = box.getBorderArea(); + v = (radius.vertical.value / 100) * area.height; } else { v = resolveEm(radius.vertical.value, this.fontSize) as number; } @@ -1129,9 +1136,9 @@ function resolveEm( } else if (value.unit === "in") { return value.value * 96; } - } else { - return value; - } + } + // handles unit === "%" as well as number + return value; } function computeStyle(parentStyle: Style, cascadedStyle: DeclaredStyle) { From 4dd8f0b6d1536675351a5f165839c947413b76d8 Mon Sep 17 00:00:00 2001 From: Bob Pritchett <26860966+BobPritchett@users.noreply.github.com> Date: Thu, 25 Sep 2025 14:10:06 -0700 Subject: [PATCH 11/11] resolveEm takes values that may have units --- src/style.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/style.ts b/src/style.ts index 529e656..145a25a 100644 --- a/src/style.ts +++ b/src/style.ts @@ -758,7 +758,7 @@ export class Style { } else if ( typeof radius === "object" && "value" in radius && "unit" in radius ) { // em and fixed length units // TODO: check if this is correct -- can we count on it being a number here? - return { horizontal: resolveEm(radius.value, this.fontSize) as number, vertical: resolveEm(radius.value, this.fontSize) as number }; + return { horizontal: resolveEm(radius, this.fontSize) as number, vertical: resolveEm(radius, this.fontSize) as number }; } else if ( typeof radius === "object" && "horizontal" in radius && "vertical" in radius ) { let h = 0; @@ -770,7 +770,7 @@ export class Style { const area = box.getBorderArea(); h = (radius.horizontal.value / 100) * area.width; } else { - h = resolveEm(radius.horizontal.value, this.fontSize) as number; + h = resolveEm(radius.horizontal, this.fontSize) as number; } } if ( typeof radius.vertical === "number" ) { @@ -780,7 +780,7 @@ export class Style { const area = box.getBorderArea(); v = (radius.vertical.value / 100) * area.height; } else { - v = resolveEm(radius.vertical.value, this.fontSize) as number; + v = resolveEm(radius.vertical, this.fontSize) as number; } } return { horizontal: h, vertical: v };