Text/number/hex inputs keep local state and commit on 150ms idle, blur or
Enter through the continuous setters; native colour pickers get an
onContinuous path; ButtonStylePanel colour routes through the shared
setters. LayersPanel collectors return structural signatures/primitives
so hover and unrelated prop edits no longer rebuild the tree.
Refs #40
- utils/breakpoints.ts: single source for 767/768/991/992; head
VISIBILITY/RESPONSIVE CSS built from it (flex-stacking rule moved from
768 to the 767 mobile boundary).
- utils/responsive-style.ts: styleTablet/styleMobile partial overrides,
cascade resolution, pure setters, scoped @media CSS per node.
- state/DeviceContext.tsx: real DeviceProvider (owns the one-time mobile
forcing from EditorShell); TopBar, overflow menu, ReportIssueModal and
Canvas read useDevice() instead of props.
- editor/RenderNode.tsx: resolves the effective style for the current
device in one place and marks overridden nodes with data-wsb-overridden.
Craft passes an opaque <DefaultRender/> to onRender, so the component
element is rebuilt with the resolved style (cloneElement cannot work).
- utils/html-export.ts: hidden nodes skipped; overrides emitted as one
body-level <style data-wsb-responsive> block + data-wsb-r scope attr;
injectAttrs skips leading <style> elements.
- test-utils/editorHarness.tsx: optional onRender/wrap options.
Refs #45
Refs #37
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CollapsibleSection persists open/closed per section title via local-prefs.
Container/Section/Columns drop the shorthand padding preset grid; the
per-side Padding control expands a legacy shorthand and writes all four
longhands in one undo step (new SpacingControl onChangeAll).
Refs #35
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Craft records actions.deserialize as an undoable step and nothing cleared
history, so Undo right after load returned the canvas to the blank pre-load
Frame (autosave would then save it), and Undo after a page switch put the
previous page's content into the current slot.
- clear history after the load-time deserialize and after every page/
header/footer switch (in-place AI replacement of the same slot keeps it)
- continuousSetProp opens a burst only when its first call actually
changed something, so it never merges into an entry it did not create
- the empty-save banner's Undo is disabled when there is nothing to undo
Real-editor tests: load, page/header switch, no-op-first burst, banner.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Mocked unit tests for regenerateTreeIds, TemplateModal.addTemplateComponents,
and buildNodeTree each let a real bug ship (DataCloneError on duplicate/paste,
dropped template children, no-op AI section-replace/insert) because their
fake @craftjs/core query/actions never exercised Craft's real node shape
(data.type as a live component reference) or real parseFreshNode validation.
Adds src/test-utils/editorHarness.tsx, which mounts a REAL <Editor>+<Frame>
(no vi.mock('@craftjs/core') anywhere) via react-dom/client + act, plus the
jsdom shims Craft/this component library actually needs (ResizeObserver,
matchMedia, and an HTMLElement.prototype.innerText polyfill -- jsdom has no
native innerText, which Heading/TextBlock rely on to paint their text).
Adds 3 integration suites under src/test-utils/integration/ driving the real
useNodeActions/useKeyboardShortcuts, TemplateModal's real tree-build pipeline,
and the real useApplyAiResponse hook against a live EditorStore, asserting on
both the real rendered DOM and query.serialize()/exportBodyHtml output.
Red-proofed the duplicate/paste suite: temporarily reverted
regenerateTreeIds to structuredClone(oldNode.data) and confirmed both tests
fail with the historical DataCloneError before restoring the fix.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>