-
Notifications
You must be signed in to change notification settings - Fork 32
add fit-content support for code block width to theme #6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -225,6 +225,25 @@ function layoutList(node: ListNode, context: LayoutContext): LayoutResult<ListFr | |||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| function parseWidth(width: number | string, containerWidth: number): number { | ||||||||||||||||||||||||||
| if (typeof width === 'number') { | ||||||||||||||||||||||||||
| return width > 0 ? width : containerWidth | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| if (width === 'fit-content') { | ||||||||||||||||||||||||||
| return -1 | ||||||||||||||||||||||||||
|
Comment on lines
+228
to
+233
|
||||||||||||||||||||||||||
| function parseWidth(width: number | string, containerWidth: number): number { | |
| if (typeof width === 'number') { | |
| return width > 0 ? width : containerWidth | |
| } | |
| if (width === 'fit-content') { | |
| return -1 | |
| function parseWidth(width: number | string, containerWidth: number): number | undefined { | |
| if (typeof width === 'number') { | |
| return width > 0 ? width : containerWidth | |
| } | |
| if (width === 'fit-content') { | |
| return undefined |
Copilot
AI
Apr 10, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
layoutCode calculates lineWidth from context.width before applying the new theme.blocks.code.width. If a theme sets code width smaller than the container (e.g. 50% or a number), the code lines will be laid out with a wider max width than the final box, so lines can extend outside box.width (background/outline) and violate the existing invariant that line.width <= box.width - padding*2. Consider computing the desired box width first (for non-fit-content values) and deriving lineWidth from that width (fall back to container width only for fit-content).
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -93,7 +93,7 @@ export type Theme = { | |||||
| paragraph: { marginBottom: number } | ||||||
| heading: { marginTop: number; marginBottom: number } | ||||||
| list: { marginBottom: number; itemGap: number; indent: number } | ||||||
| code: { marginBottom: number; padding: number } | ||||||
| code: { marginBottom: number; padding: number, width: number | string } | ||||||
|
||||||
| code: { marginBottom: number; padding: number, width: number | string } | |
| code: { marginBottom: number; padding: number; width?: number | string } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,53 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { test, expect } from "bun:test"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Copy parseWidth function for testing | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function parseWidth(width: number | string, containerWidth: number): number { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (typeof width === 'number') { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return width > 0 ? width : containerWidth | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (width === 'fit-content') { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return -1 // Special marker for caller to handle | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Support percentage format like "50%", "80%" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const match = width.match(/^(\d+(?:\.\d+)?)%$/) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (match && match[1]) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const percentage = parseFloat(match[1]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!isNaN(percentage) && percentage > 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return (containerWidth * percentage) / 100 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Default to container width | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return containerWidth | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| test("parseWidth: number > 0 returns the number itself", () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(parseWidth(100, 500)).toBe(100) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(parseWidth(300, 500)).toBe(300) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| test("parseWidth: number <= 0 returns container width", () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(parseWidth(0, 500)).toBe(500) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(parseWidth(-10, 500)).toBe(500) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| test("parseWidth: fit-content returns -1", () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(parseWidth('fit-content', 500)).toBe(-1) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| test("parseWidth: percentage strings", () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(parseWidth('50%', 500)).toBe(250) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(parseWidth('100%', 500)).toBe(500) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(parseWidth('25%', 400)).toBe(100) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| test("parseWidth: decimal percentages", () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(parseWidth('33.33%', 300)).toBeCloseTo(99.99) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(parseWidth('66.66%', 300)).toBeCloseTo(199.98) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| test("parseWidth: invalid percentages return container width", () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(parseWidth('abc', 500)).toBe(500) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(parseWidth('50', 500)).toBe(500) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(parseWidth('50 px', 500)).toBe(500) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| expect(parseWidth('', 500)).toBe(500) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+1
to
+53
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { test, expect } from "bun:test"; | |
| // Copy parseWidth function for testing | |
| function parseWidth(width: number | string, containerWidth: number): number { | |
| if (typeof width === 'number') { | |
| return width > 0 ? width : containerWidth | |
| } | |
| if (width === 'fit-content') { | |
| return -1 // Special marker for caller to handle | |
| } | |
| // Support percentage format like "50%", "80%" | |
| const match = width.match(/^(\d+(?:\.\d+)?)%$/) | |
| if (match && match[1]) { | |
| const percentage = parseFloat(match[1]) | |
| if (!isNaN(percentage) && percentage > 0) { | |
| return (containerWidth * percentage) / 100 | |
| } | |
| } | |
| // Default to container width | |
| return containerWidth | |
| } | |
| test("parseWidth: number > 0 returns the number itself", () => { | |
| expect(parseWidth(100, 500)).toBe(100) | |
| expect(parseWidth(300, 500)).toBe(300) | |
| }) | |
| test("parseWidth: number <= 0 returns container width", () => { | |
| expect(parseWidth(0, 500)).toBe(500) | |
| expect(parseWidth(-10, 500)).toBe(500) | |
| }) | |
| test("parseWidth: fit-content returns -1", () => { | |
| expect(parseWidth('fit-content', 500)).toBe(-1) | |
| }) | |
| test("parseWidth: percentage strings", () => { | |
| expect(parseWidth('50%', 500)).toBe(250) | |
| expect(parseWidth('100%', 500)).toBe(500) | |
| expect(parseWidth('25%', 400)).toBe(100) | |
| }) | |
| test("parseWidth: decimal percentages", () => { | |
| expect(parseWidth('33.33%', 300)).toBeCloseTo(99.99) | |
| expect(parseWidth('66.66%', 300)).toBeCloseTo(199.98) | |
| }) | |
| test("parseWidth: invalid percentages return container width", () => { | |
| expect(parseWidth('abc', 500)).toBe(500) | |
| expect(parseWidth('50', 500)).toBe(500) | |
| expect(parseWidth('50 px', 500)).toBe(500) | |
| expect(parseWidth('', 500)).toBe(500) | |
| }) | |
| import { test } from "bun:test"; | |
| test.todo( | |
| "layoutDocument/layoutCode applies a positive numeric blocks.code.width as an explicit width", | |
| ); | |
| test.todo( | |
| "layoutDocument/layoutCode falls back to the container width when blocks.code.width is 0 or negative", | |
| ); | |
| test.todo( | |
| "layoutDocument/layoutCode preserves fit-content behavior when blocks.code.width is 'fit-content'", | |
| ); | |
| test.todo( | |
| "layoutDocument/layoutCode supports percentage widths such as '50%' and '100%' via the production parser", | |
| ); | |
| test.todo( | |
| "layoutDocument/layoutCode supports decimal percentage widths such as '33.33%' via the production parser", | |
| ); | |
| test.todo( | |
| "layoutDocument/layoutCode falls back to the container width for invalid width strings", | |
| ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
parseWidthcurrently allows numeric widths greater thancontainerWidth(and percentages > 100%) to pass through unchanged, which can cause code blocks to render outside the page content area. If overflow isn’t intended, consider clamping parsed widths to[1, containerWidth](and similarly clamping computed percentages).