@zseven-w/pen-core 0.7.1 → 0.7.3
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.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zseven-w/pen-core",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.3",
|
|
4
4
|
"description": "Core document operations, tree utils, variables, layout engine for OpenPencil",
|
|
5
5
|
"homepage": "https://github.com/ZSeven-W/openpencil/tree/main/packages/pen-core",
|
|
6
6
|
"bugs": {
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"typecheck": "tsc --noEmit"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@zseven-w/pen-types": "0.7.
|
|
33
|
+
"@zseven-w/pen-types": "0.7.3",
|
|
34
34
|
"nanoid": "^5.1.6",
|
|
35
35
|
"paper": "^0.12.18"
|
|
36
36
|
},
|
|
@@ -235,6 +235,58 @@ describe('stripRedundantSectionFills', () => {
|
|
|
235
235
|
expect((deepInner as PenNode & { fill?: unknown }).fill).toEqual(solidFill('#0A0A0A'));
|
|
236
236
|
});
|
|
237
237
|
|
|
238
|
+
it('strips stale #FFFFFF section fills on a dark root (legacy alternation residue)', () => {
|
|
239
|
+
// Regression guard for 2026-04-15: the legacy fixSectionAlternation
|
|
240
|
+
// painted #FFFFFF / #F8FAFC on unfilled section runs regardless of
|
|
241
|
+
// page theme. After the alternation skip for dark parents landed,
|
|
242
|
+
// stale docs (and weak-model hedges) still carry those whites.
|
|
243
|
+
// stripRedundantSectionFills must now clean them up.
|
|
244
|
+
const section1 = frame({
|
|
245
|
+
id: 's1',
|
|
246
|
+
name: 'Hero',
|
|
247
|
+
role: 'hero',
|
|
248
|
+
fill: solidFill('#FFFFFF'),
|
|
249
|
+
});
|
|
250
|
+
const section2 = frame({
|
|
251
|
+
id: 's2',
|
|
252
|
+
name: 'Stats',
|
|
253
|
+
role: 'stats-section',
|
|
254
|
+
fill: solidFill('#F8FAFC'),
|
|
255
|
+
});
|
|
256
|
+
const section3 = frame({
|
|
257
|
+
id: 's3',
|
|
258
|
+
name: 'CTA',
|
|
259
|
+
role: 'cta-section',
|
|
260
|
+
fill: solidFill('#FFFFFF'),
|
|
261
|
+
});
|
|
262
|
+
const root = frame({
|
|
263
|
+
id: 'root',
|
|
264
|
+
fill: solidFill('#111111'),
|
|
265
|
+
children: [section1, section2, section3],
|
|
266
|
+
});
|
|
267
|
+
const changed = stripRedundantSectionFills(root);
|
|
268
|
+
expect(changed).toBe(true);
|
|
269
|
+
expect((section1 as PenNode & { fill?: unknown }).fill).toBeUndefined();
|
|
270
|
+
expect((section2 as PenNode & { fill?: unknown }).fill).toBeUndefined();
|
|
271
|
+
expect((section3 as PenNode & { fill?: unknown }).fill).toBeUndefined();
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
it('strips a safe-light hedge even when the root has no fill', () => {
|
|
275
|
+
// Mirror of the existing "root frame without a fill" dark case: a
|
|
276
|
+
// bare #FFFFFF on a section root is almost certainly the sub-agent
|
|
277
|
+
// hedging against a missing background spec, not a deliberate choice.
|
|
278
|
+
const section = frame({
|
|
279
|
+
id: 'sec',
|
|
280
|
+
fill: solidFill('#FAFAFA'),
|
|
281
|
+
});
|
|
282
|
+
const root = frame({
|
|
283
|
+
id: 'root',
|
|
284
|
+
children: [section],
|
|
285
|
+
});
|
|
286
|
+
stripRedundantSectionFills(root);
|
|
287
|
+
expect((section as PenNode & { fill?: unknown }).fill).toBeUndefined();
|
|
288
|
+
});
|
|
289
|
+
|
|
238
290
|
it('reproduces the M2.7 health-tracker case', () => {
|
|
239
291
|
// Direct repro of the actual failure: root #1a1a2e, six section roots
|
|
240
292
|
// all hardcoded #0A0A0A, including one real card. The six section
|
|
@@ -126,13 +126,41 @@ const SAFE_DARK_HEXES = new Set([
|
|
|
126
126
|
'#202020',
|
|
127
127
|
]);
|
|
128
128
|
|
|
129
|
+
/**
|
|
130
|
+
* Light-mode counterparts of SAFE_DARK_HEXES. Two sources produce these
|
|
131
|
+
* on section roots:
|
|
132
|
+
* 1. Weaker sub-agents that hedge with pure white / near-white instead
|
|
133
|
+
* of the role-correct transparent fill.
|
|
134
|
+
* 2. The legacy `fixSectionAlternation` post-pass that painted an
|
|
135
|
+
* #FFFFFF / #F8FAFC ladder on every run of ≥3 unfilled sections.
|
|
136
|
+
* On dark pages that ladder leaves visible white strips; if a doc
|
|
137
|
+
* with those stale fills is re-opened or re-rendered after the
|
|
138
|
+
* alternation skip landed, the fills are still there and the skip
|
|
139
|
+
* alone won't remove them.
|
|
140
|
+
* Treat these the same as safe-dark hedges: strip on any section root.
|
|
141
|
+
*/
|
|
142
|
+
const SAFE_LIGHT_HEXES = new Set([
|
|
143
|
+
'#ffffff',
|
|
144
|
+
'#fff',
|
|
145
|
+
'#fefefe',
|
|
146
|
+
'#fdfdfd',
|
|
147
|
+
'#fcfcfc',
|
|
148
|
+
'#fafafa',
|
|
149
|
+
'#f9fafb',
|
|
150
|
+
'#f8f8f8',
|
|
151
|
+
'#f8fafc',
|
|
152
|
+
'#f5f5f5',
|
|
153
|
+
'#f4f4f5',
|
|
154
|
+
'#f3f4f6',
|
|
155
|
+
]);
|
|
156
|
+
|
|
129
157
|
function shouldStripFill(childFill: string, rootFill: string | null): boolean {
|
|
130
158
|
const childKey = normalizeHex(childFill);
|
|
131
159
|
if (rootFill) {
|
|
132
160
|
const rootKey = normalizeHex(rootFill);
|
|
133
161
|
if (childKey === rootKey) return true;
|
|
134
162
|
}
|
|
135
|
-
return SAFE_DARK_HEXES.has(childKey);
|
|
163
|
+
return SAFE_DARK_HEXES.has(childKey) || SAFE_LIGHT_HEXES.has(childKey);
|
|
136
164
|
}
|
|
137
165
|
|
|
138
166
|
function normalizeHex(color: string): string {
|