fix(worksheets): correct Typst array membership syntax for ten-frames rendering

Fix ten-frames not rendering on worksheets when scaffolding rules called for them.

The issue was in the Typst template code using incorrect syntax for checking
array membership. Typst requires `.contains(item)` method, not `(item in array)`.

Changes:
- typstHelpers.ts:203: Change `(i in regrouping-places)` to `regrouping-places.contains(i)`
- answerRow.ts:52: Change `(i in borrow-places)` to `borrow-places.contains(i)`

This was causing `shows-frame` to evaluate incorrectly, preventing ten-frames
from rendering even when displayRules.tenFrames was set to 'whenRegrouping'
and the problem had actual regrouping.

Affects both addition and subtraction worksheets.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Thomas Hallock 2025-11-10 09:53:19 -06:00
parent 26a08859d7
commit 14b359462f
2 changed files with 46 additions and 59 deletions

View File

@ -5,16 +5,16 @@
// for backward compatibility. New code should import from typstHelpers/ directly.
// Import types for internal use
import type { DisplayOptions } from "./typstHelpers/shared/types";
import type { DisplayOptions } from './typstHelpers/shared/types'
// Re-export everything from modular structure
export type {
DisplayOptions,
CellDimensions,
} from "./typstHelpers/shared/types";
export { generateTypstHelpers } from "./typstHelpers/shared/helpers";
export { generatePlaceValueColors } from "./typstHelpers/shared/colors";
export { generateSubtractionProblemStackFunction } from "./typstHelpers/subtraction/problemStack";
} from './typstHelpers/shared/types'
export { generateTypstHelpers } from './typstHelpers/shared/helpers'
export { generatePlaceValueColors } from './typstHelpers/shared/colors'
export { generateSubtractionProblemStackFunction } from './typstHelpers/subtraction/problemStack'
/**
* Generate Typst function for rendering problem stack/grid
@ -24,23 +24,20 @@ export { generateSubtractionProblemStackFunction } from "./typstHelpers/subtract
* @param cellSize Size of each digit cell in inches
* @param maxDigits Maximum number of digits in any problem on this page (1-6)
*/
export function generateProblemStackFunction(
cellSize: number,
maxDigits: number = 3,
): string {
const cellSizeIn = `${cellSize}in`;
const cellSizePt = cellSize * 72;
export function generateProblemStackFunction(cellSize: number, maxDigits: number = 3): string {
const cellSizeIn = `${cellSize}in`
const cellSizePt = cellSize * 72
// Generate place value color assignments (unique color per place value)
// Index 0 = ones, 1 = tens, 2 = hundreds, 3 = thousands, 4 = ten-thousands, 5 = hundred-thousands
const placeColors = [
"color-ones", // 0: ones (light blue)
"color-tens", // 1: tens (light green)
"color-hundreds", // 2: hundreds (light yellow)
"color-thousands", // 3: thousands (light pink/rose)
"color-ten-thousands", // 4: ten-thousands (light purple/lavender)
"color-hundred-thousands", // 5: hundred-thousands (light peach/orange)
];
'color-ones', // 0: ones (light blue)
'color-tens', // 1: tens (light green)
'color-hundreds', // 2: hundreds (light yellow)
'color-thousands', // 3: thousands (light pink/rose)
'color-ten-thousands', // 4: ten-thousands (light purple/lavender)
'color-hundred-thousands', // 5: hundred-thousands (light peach/orange)
]
return String.raw`
// Problem rendering function for addition worksheets (supports 1-${maxDigits} digit problems)
@ -48,7 +45,7 @@ export function generateProblemStackFunction(
// Per-problem display flags: show-carries, show-answers, show-colors, show-ten-frames, show-numbers
#let problem-stack(a, b, index-or-none, show-carries, show-answers, show-colors, show-ten-frames, show-numbers) = {
// Place value colors array for dynamic lookup (index 0 = ones, 1 = tens, ...)
let place-colors = (${placeColors.join(", ")})
let place-colors = (${placeColors.join(', ')})
// Extract digits dynamically based on problem size
let max-digits = ${maxDigits}
@ -203,7 +200,7 @@ export function generateProblemStackFunction(
[], // Empty cell for + sign column
// Show ten-frames for any place value that needs regrouping
..for i in range(0, actual-digits).rev() {
let shows-frame = show-ten-frames-for-all or (i in regrouping-places)
let shows-frame = show-ten-frames-for-all or regrouping-places.contains(i)
if shows-frame {
// Show ten-frame for this place value
// Top frame: carry destination (next higher place value)
@ -246,7 +243,7 @@ export function generateProblemStackFunction(
)
)
}
`;
`
}
/**
@ -274,10 +271,10 @@ export function generateProblemTypst(
addend2: number,
cellSize: number,
options: DisplayOptions,
problemNumber?: number,
problemNumber?: number
): string {
const cellSizeIn = `${cellSize}in`;
const cellSizePt = cellSize * 72;
const cellSizeIn = `${cellSize}in`
const cellSizePt = cellSize * 72
return String.raw`
#let a = ${addend1}
@ -299,7 +296,7 @@ export function generateProblemTypst(
#text(size: ${(cellSizePt * 0.6).toFixed(1)}pt, weight: "bold", font: "New Computer Modern Math")[\\#${problemNumber}.]
]
],`
: ""
: ''
}
grid(
columns: (0.5em, ${cellSizeIn}, ${cellSizeIn}, ${cellSizeIn}),
@ -310,41 +307,31 @@ export function generateProblemTypst(
${
options.showCarryBoxes
? options.showPlaceValueColors
? "diagonal-split-box(" +
cellSizeIn +
", color-tens, color-hundreds),"
: "box(width: " +
cellSizeIn +
", height: " +
cellSizeIn +
", stroke: 0.5pt)[],"
: "v(" + cellSizeIn + "),"
? 'diagonal-split-box(' + cellSizeIn + ', color-tens, color-hundreds),'
: 'box(width: ' + cellSizeIn + ', height: ' + cellSizeIn + ', stroke: 0.5pt)[],'
: 'v(' + cellSizeIn + '),'
}
// Tens carry box: shows carry FROM ones (blue) TO tens (green)
${
options.showCarryBoxes
? options.showPlaceValueColors
? "diagonal-split-box(" + cellSizeIn + ", color-ones, color-tens),"
: "box(width: " +
cellSizeIn +
", height: " +
cellSizeIn +
", stroke: 0.5pt)[],"
: "v(" + cellSizeIn + "),"
? 'diagonal-split-box(' + cellSizeIn + ', color-ones, color-tens),'
: 'box(width: ' + cellSizeIn + ', height: ' + cellSizeIn + ', stroke: 0.5pt)[],'
: 'v(' + cellSizeIn + '),'
}
[],
// First addend
[],
box(width: ${cellSizeIn}, height: ${cellSizeIn}, fill: ${options.showPlaceValueColors ? "color-hundreds" : "color-none"})[#align(center + horizon)[#if aH > 0 [#aH] else [#h(0pt)]]],
box(width: ${cellSizeIn}, height: ${cellSizeIn}, fill: ${options.showPlaceValueColors ? "color-tens" : "color-none"})[#align(center + horizon)[#aT]],
box(width: ${cellSizeIn}, height: ${cellSizeIn}, fill: ${options.showPlaceValueColors ? "color-ones" : "color-none"})[#align(center + horizon)[#aO]],
box(width: ${cellSizeIn}, height: ${cellSizeIn}, fill: ${options.showPlaceValueColors ? 'color-hundreds' : 'color-none'})[#align(center + horizon)[#if aH > 0 [#aH] else [#h(0pt)]]],
box(width: ${cellSizeIn}, height: ${cellSizeIn}, fill: ${options.showPlaceValueColors ? 'color-tens' : 'color-none'})[#align(center + horizon)[#aT]],
box(width: ${cellSizeIn}, height: ${cellSizeIn}, fill: ${options.showPlaceValueColors ? 'color-ones' : 'color-none'})[#align(center + horizon)[#aO]],
// Second addend with + sign
[+],
box(width: ${cellSizeIn}, height: ${cellSizeIn}, fill: ${options.showPlaceValueColors ? "color-hundreds" : "color-none"})[#align(center + horizon)[#if bH > 0 [#bH] else [#h(0pt)]]],
box(width: ${cellSizeIn}, height: ${cellSizeIn}, fill: ${options.showPlaceValueColors ? "color-tens" : "color-none"})[#align(center + horizon)[#bT]],
box(width: ${cellSizeIn}, height: ${cellSizeIn}, fill: ${options.showPlaceValueColors ? "color-ones" : "color-none"})[#align(center + horizon)[#bO]],
box(width: ${cellSizeIn}, height: ${cellSizeIn}, fill: ${options.showPlaceValueColors ? 'color-hundreds' : 'color-none'})[#align(center + horizon)[#if bH > 0 [#bH] else [#h(0pt)]]],
box(width: ${cellSizeIn}, height: ${cellSizeIn}, fill: ${options.showPlaceValueColors ? 'color-tens' : 'color-none'})[#align(center + horizon)[#bT]],
box(width: ${cellSizeIn}, height: ${cellSizeIn}, fill: ${options.showPlaceValueColors ? 'color-ones' : 'color-none'})[#align(center + horizon)[#bO]],
// Horizontal line
[],
@ -359,7 +346,7 @@ export function generateProblemTypst(
box(width: ${cellSizeIn}, height: ${cellSizeIn}, fill: color-none, stroke: grid-stroke, inset: 0pt)[],
box(width: ${cellSizeIn}, height: ${cellSizeIn}, fill: color-none, stroke: grid-stroke, inset: 0pt)[],
box(width: ${cellSizeIn}, height: ${cellSizeIn}, fill: color-none, stroke: grid-stroke, inset: 0pt)[],`
: ""
: ''
}
)${
options.showTenFrames || options.showTenFramesForAll
@ -368,8 +355,8 @@ export function generateProblemTypst(
box(inset: 2pt)[
#ten-frames-stacked(${cellSizeIn}, color-ones, color-tens)
]`
: ""
: ''
}
)
`;
`
}

View File

@ -1,8 +1,8 @@
// Answer row and ten-frames rendering for subtraction problems
// Shows answer boxes and optional borrowing visualization
import type { CellDimensions } from "../shared/types";
import { TYPST_CONSTANTS } from "../shared/types";
import type { CellDimensions } from '../shared/types'
import { TYPST_CONSTANTS } from '../shared/types'
/**
* Generate Typst code for the line row (separates problem from answer)
@ -11,7 +11,7 @@ import { TYPST_CONSTANTS } from "../shared/types";
* @returns Typst code for line row
*/
export function generateLineRow(cellDimensions: CellDimensions): string {
const { cellSizeIn } = cellDimensions;
const { cellSizeIn } = cellDimensions
return String.raw`
// Line row
@ -19,7 +19,7 @@ export function generateLineRow(cellDimensions: CellDimensions): string {
..for i in range(0, grid-digits) {
(line(length: ${cellSizeIn}, stroke: heavy-stroke),)
},
`;
`
}
/**
@ -32,7 +32,7 @@ export function generateLineRow(cellDimensions: CellDimensions): string {
* @returns Typst code for ten-frames row
*/
export function generateTenFramesRow(cellDimensions: CellDimensions): string {
const { cellSizeIn } = cellDimensions;
const { cellSizeIn } = cellDimensions
return String.raw`
// Ten-frames row (show borrowing visualization)
@ -49,7 +49,7 @@ export function generateTenFramesRow(cellDimensions: CellDimensions): string {
(
[], // Empty cell for operator column
..for i in range(0, grid-digits).rev() {
let shows-frame = show-ten-frames-for-all or (i in borrow-places)
let shows-frame = show-ten-frames-for-all or borrow-places.contains(i)
if shows-frame {
// Show borrowed amount visualization
@ -77,7 +77,7 @@ export function generateTenFramesRow(cellDimensions: CellDimensions): string {
} else {
()
},
`;
`
}
/**
@ -90,7 +90,7 @@ export function generateTenFramesRow(cellDimensions: CellDimensions): string {
* @returns Typst code for answer boxes row
*/
export function generateAnswerBoxesRow(cellDimensions: CellDimensions): string {
const { cellSizeIn } = cellDimensions;
const { cellSizeIn } = cellDimensions
return String.raw`
// Answer boxes (only for actual difference digits, hiding leading zeros)
@ -111,5 +111,5 @@ export function generateAnswerBoxesRow(cellDimensions: CellDimensions): string {
],)
}
},
`;
`
}