Skip to content
Merged
Changes from 1 commit
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
8745297
test(print): define paged-media stylesheet contract
seonghobae Aug 10, 2026
f70f522
test(print): keep stylesheet contract static-analysis-safe
seonghobae Aug 10, 2026
bc32643
feat(print): add paged-media-safe editor styles
seonghobae Aug 10, 2026
ae12d0f
docs(print): define browser paged-output contract
seonghobae Aug 10, 2026
f598190
docs(doctoring): trace browser print standards
seonghobae Aug 10, 2026
db6644d
docs(print): index browser print contract
seonghobae Aug 10, 2026
c82f2ac
test(docs): bind browser print authority
seonghobae Aug 10, 2026
73e2a3e
test(print): verify real-engine print media behavior
seonghobae Aug 10, 2026
01ee9e8
test(print): run print contract across browser engines
seonghobae Aug 10, 2026
a813ff9
test(print): exercise real empty-editor placeholder state
seonghobae Aug 10, 2026
841d19b
fix(print): feature-detect widow and orphan CSS
seonghobae Aug 10, 2026
f3f24db
test(print): require packed stylesheet evidence
seonghobae Aug 10, 2026
94e9a10
docs(print): use canonical active proposal status
seonghobae Aug 10, 2026
bc87941
docs(print): bind evidence to packaged stylesheet
seonghobae Aug 10, 2026
660c55a
test(print): require canonical proposal status
seonghobae Aug 10, 2026
6833896
Merge branch 'main' into feat/print-paged-media
opencode-agent[bot] Aug 10, 2026
ce1259d
Merge branch 'main' into feat/print-paged-media
opencode-agent[bot] Aug 10, 2026
5d615c5
test(print): bind evidence to packaged stylesheet semantics
seonghobae Aug 10, 2026
3a35ba0
test(print): exercise the packaged stylesheet in real browsers
seonghobae Aug 10, 2026
a3f3626
test(print): build package styles before browser evidence
seonghobae Aug 10, 2026
ab5f924
Merge branch 'main' into feat/print-paged-media
opencode-agent[bot] Aug 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions src/printStyles.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { readFileSync } from 'node:fs';
import { resolve } from 'node:path';

import { describe, expect, it } from 'vitest';

const styles = readFileSync(resolve(process.cwd(), 'src/styles.css'), 'utf8');

/** Match one CSS rule body for an exact selector within the shipped stylesheet. */
function ruleBody(selector: string): string {
const escaped = selector.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
const match = styles.match(new RegExp(`${escaped}\\s*\\{([^}]*)\\}`, 'u'));
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
if (!match?.[1]) throw new Error(`Missing CSS rule for ${selector}`);
return match[1];
}

describe('print stylesheet contract', () => {
it('defines an explicit paged-document print media boundary', () => {
expect(styles).toMatch(/@media\s+print\s*\{/u);

Check failure on line 18 in src/printStyles.test.ts

View workflow job for this annotation

GitHub Actions / build-and-test

src/printStyles.test.ts > print stylesheet contract > defines an explicit paged-document print media boundary

AssertionError: expected '/* cwl-editor (Inkspan) — self-contai…' to match /@media\s+print\s*\{/u - Expected: /@media\s+print\s*\{/u + Received: "/* cwl-editor (Inkspan) — self-contained, theme-aware styles. Import once: import '@contextualwisdomlab/cwl-editor/styles.css'; For the BUNDLED offline multilingual fonts (KR / EN+VI / JP / SC / TC) also: import '@contextualwisdomlab/cwl-editor/fonts.css'; // all 5 scripts import '@contextualwisdomlab/cwl-editor/fonts-latin.css'; // Latin/VI only All colors are driven by CSS variables so hosts can re-theme via KV/props. The default font stack lists the bundled Noto Sans families first so, once fonts.css is imported, all five scripts render offline; it falls back to the platform UI fonts when fonts.css is not loaded. */ .cwl-editor { --cwl-fg: #1f2328; --cwl-muted: #59636e; --cwl-border: #d1d9e0; --cwl-bg: #ffffff; --cwl-surface: #f6f8fa; --cwl-accent: #0969da; --cwl-accent-soft: #ddf4ff; --cwl-radius: 8px; /* Bundled Noto Sans stack: covers Latin/Vietnamese + Korean + Japanese + Simplified & Traditional Chinese. Override --cwl-font to re-theme. */ --cwl-font: 'Noto Sans', 'Noto Sans KR', 'Noto Sans JP', 'Noto Sans SC', 'Noto Sans TC', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; color: var(--cwl-fg); background: var(--cwl-bg); border: 1px solid var(--cwl-border); border-radius: var(--cwl-radius); font-family: var(--cwl-font); display: flex; flex-direction: column; overflow: hidden; } @media (prefers-color-scheme: dark) { .cwl-editor { --cwl-fg: #e6edf3; --cwl-muted: #9198a1; --cwl-border: #3d444d; --cwl-bg: #0d1117; --cwl-surface: #161b22; --cwl-accent: #4493f8; --cwl-accent-soft: #163356; } } .cwl-toolbar { display: flex; flex-wrap: wrap; gap: 4px; padding: 6px 8px; background: var(--cwl-surface); border-bottom: 1px solid var(--cwl-border); position: sticky; top: 0; z-index: 2; } .cwl-toolbar:focus-within { box-shadow: inset 0 -2px 0 var(--cwl-accent); } .cwl-tb-group { display: flex; gap: 2px; padding-right: 6px; margin-right: 4px; border-right: 1px solid var(--cwl-border); } .cwl-tb-group:last-child { border-right: none; } .cwl-tb-btn { min-width: 30px; height: 30px; padding: 0 8px; border: 1px solid transparent; border-radius: 6px; background: transparent; color: var(--cwl-fg); font-size: 13px; font-weight: 600; cursor: pointer; line-height: 1; transition: background 0.12s ease, border-color 0.12s ease; } .cwl-tb-btn:hover:not(:disabled) { background: var(--cwl-accent-soft); } .cwl-tb-btn:focus-visible { outline: 2px solid var(--cwl-accent); outline-offset: 2px; } .cwl-tb-btn.is-active { background: var(--cwl-accent-soft); border-color: var(--cwl-accent); color: var(--cwl-accent); } .cwl-tb-btn:disabled { opacity: 0.4; cursor: not-allowed; } @media (forced-colors: active) { .cwl-tb-btn:focus-visible { outline-color: CanvasText; } } .cwl-editor__surface { overflow-y: auto; max-height: 70vh; } .cwl-editor__content { padding: 16px 20px; min-height: 200px; outline: none; line-height: 1.6; font-size: 15px; } .cwl-editor__content:focus { outline: none; } .cwl-editor__content > * + * { margin-top: 0.75em; } .cwl-editor__content h1 { font-size: 1.8em; font-weight: 700; } .cwl-editor__content h2 { font-size: 1.5em; font-weight: 700; } .cwl-editor__content h3 { font-size: 1.25em; font-weight: 600; } .cwl-editor__content ul, .cwl-editor__content ol { padding-left: 1.5em; } .cwl-editor__content a { color: var(--cwl-accent); text-decoration: underline; } .cwl-editor__content code { background: var(--cwl-surface); border: 1px solid var(--cwl-border); border-radius: 4px; padding: 0.1em 0.35em; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 0.9em; } .cwl-editor__content pre { background: var(--cwl-surface); border: 1px solid var(--
});

it('removes screen-only clipping and interactive chrome from printed output', () => {
const printIndex = styles.indexOf('@media print');
expect(printIndex).toBeGreaterThan(-1);

Check failure on line 23 in src/printStyles.test.ts

View workflow job for this annotation

GitHub Actions / build-and-test

src/printStyles.test.ts > print stylesheet contract > removes screen-only clipping and interactive chrome from printed output

AssertionError: expected -1 to be greater than -1 ❯ src/printStyles.test.ts:23:24
const printStyles = styles.slice(printIndex);

expect(printStyles).toMatch(
/\.cwl-toolbar[\s\S]*\.cwl-collaboration-status[\s\S]*\.collaboration-cursor__caret[\s\S]*\.collaboration-cursor__label[\s\S]*\{[^}]*display:\s*none\s*!important\s*;/u,
);
expect(printStyles).toMatch(
/\.cwl-editor__surface\s*\{[^}]*overflow(?:-y)?:\s*visible\s*;[^}]*max-height:\s*none\s*;/u,
);
expect(printStyles).toMatch(
/\.cwl-editor\s*\{[^}]*overflow:\s*visible\s*;[^}]*border:\s*0\s*;/u,
);
});

it('does not print placeholder UI and keeps document blocks page-safe', () => {
const printIndex = styles.indexOf('@media print');
expect(printIndex).toBeGreaterThan(-1);

Check failure on line 39 in src/printStyles.test.ts

View workflow job for this annotation

GitHub Actions / build-and-test

src/printStyles.test.ts > print stylesheet contract > does not print placeholder UI and keeps document blocks page-safe

AssertionError: expected -1 to be greater than -1 ❯ src/printStyles.test.ts:39:24
const printStyles = styles.slice(printIndex);

expect(printStyles).toMatch(
/\.cwl-editor__content \.is-editor-empty:first-child::before\s*\{[^}]*content:\s*none\s*;/u,
);
expect(printStyles).toMatch(/break-inside:\s*avoid\s*;/u);
expect(printStyles).toMatch(/break-after:\s*avoid\s*;/u);
expect(printStyles).toMatch(/orphans:\s*3\s*;/u);
expect(printStyles).toMatch(/widows:\s*3\s*;/u);
});

it('keeps authored links distinguishable independently of color', () => {
expect(ruleBody('.cwl-editor__content a')).toMatch(
/text-decoration:\s*underline\s*;/u,
);
});
});
Loading