6cd60e86e8
2 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
8562711f49 |
fix(workspace+theme): sanitise corrupt spans, short-circuit re-reconcile, drop unreachable regex
──────────────────────────────────────────────────────────────────
customizable-workspace
──────────────────────────────────────────────────────────────────
Two issues caught in the audit pass:
1. **Corrupt persisted spans broke the grid layout.**
localStorage entries from older versions (or hand-edited debug
sessions) could contain span=NaN / 0 / -3 / 99. These flowed
straight into `grid-column: span <bad>` which silently broke
the whole row. The visual symptom was a tile rendering at zero
width or pushing every sibling off-screen.
Fix: `reconcile()` now clamps every span (including newly
appended tiles' defaultSpan) to the legal `[1, 4]` range via
`sanitiseSpan()`.
2. **Re-reconcile effect could loop when callers forget to memoise.**
The `useEffect([tiles, hydrated])` always called `setLayout`
with a fresh `{ entries: [...] }` object reference, even when
the content was identical. If `tiles` itself was a fresh
reference per parent render (e.g. `tiles=[{...}]` inline),
every render \u2192 setLayout \u2192 save effect \u2192 (no loop because
tiles ref same), but constant unnecessary writes to
localStorage.
Fix: added `sameLayout(a, b)` structural-equality check;
setLayout now short-circuits to the previous state when the
reconciled output is identical.
Tests: 10 \u2192 11
reconcile \u00b7 sanitises corrupt spans (NaN/0/negative/>4) \u2192 clamp
──────────────────────────────────────────────────────────────────
generative-theme
──────────────────────────────────────────────────────────────────
Cosmetic but worth fixing: the `rose` palette regex included
`warm` as a keyword, but the `citrus` palette \u2014 listed earlier in
the PALETTES table \u2014 also matched `warm`. Since first-match wins,
`warm` was unreachable in rose and the entry was misleading.
Dropped `warm` from the rose regex. Citrus retains it (was always
where it routed in practice). All 18 existing tests still pass.
|
||
|
|
2affd1aba0 |
feat(customizable-workspace): @bytelyst/customizable-workspace@0.1.0 — Wave 13.F
Drag-reorderable tile grid with per-tile width control + view-scoped
persistence. Native HTML5 drag — zero runtime deps (no @dnd-kit).
──────────────────────────────────────────────────────────────────
Module surface
──────────────────────────────────────────────────────────────────
<Workspace tiles storageKey persistence? columns? readOnly?>
Wave 13.F.1 + .2
- Native HTML5 drag-and-drop (draggable + dragover + drop)
- role=grid + per-cell role=gridcell + tabIndex=0
- Keyboard shortcuts on focused tile:
← / → resize span down/up (clamped 1..columns)
↑ / ↓ move tile up/down by one slot
- Per-tile 1/2/3/4 size buttons (suppressed in readOnly)
- Drop target gets dashed accent outline
- Reset-layout CTA (suppressed in readOnly)
useWorkspaceLayout(tiles, { storageKey, persistence })
- move(from, to) / resize(id, span) / reset()
- hydrated flag — true once initial load resolves
- One-shot load on mount, save on every change (post-hydration)
reconcile(layout, tiles) · exported pure fn
- Drops entries referencing removed tiles
- Appends new tiles in registry order with defaultSpan fallback
- Used by the hook on every tile-registry change
(defensive against schema drift between releases)
localStoragePersistence · default; SSR-safe (returns null when
window is absent)
──────────────────────────────────────────────────────────────────
Quality gates
──────────────────────────────────────────────────────────────────
✓ 10/10 tests passing
- reconcile: 3 cases (drop unknown / append new / preserve order)
- hook: 4 cases (hydrate defaults / move / resize / reset)
- component: 3 cases (renders cells / keyboard resize / readOnly)
✓ tsc build clean
──────────────────────────────────────────────────────────────────
Roadmap (lands in subsequent commit)
──────────────────────────────────────────────────────────────────
13.F.1 Drag-resize tiles
13.F.2 Saved views per route + persistence layer
Showcase /futurism/workspace (MAG.6) lands in the paired showcase
commit.
|