Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ Website-CSS kann Tailwind über semantische Layer verwenden. Dynamische Reglerwe

`DevtoolsConfig`, `Metadata`, `Target`, `Family`, `Variant`, `Range`, `Select`, `SelectOption`, `Toggle`, `DevtoolsState` sowie `defineDevtoolsConfig`, `validateConfig`, `initialState`, `validateState`, `encodeState`, `decodeState`, `stateUrl`, `applyEffects`, `changes`, `changesJson`, `agentBrief`, `resetBaseline`, `recipe` und `typescriptRecipe` sind serialisierbar bzw. strict typisiert. Nicht-kanonische Alias-Exporte werden nicht angeboten. Ungültige URL-Werte werden verworfen (fail-closed).

Das Panel startet platzsparend eingeklappt. Es bietet Reset, Permalink-, JSON- und TypeScript-Copy sowie JSON-Download. Es ist vollständig ausblendbar und per Cmd/Ctrl+Shift+D wiederherstellbar beziehungsweise umschaltbar. Tastaturfokus und Reduced Motion werden berücksichtigt. URL-State verwendet nur den Parameter `fd` und erhält vorhandene Parameter.
Das Panel startet beim ersten Aufruf geöffnet und merkt sich danach Position, aktive Ansicht und den eingeklappten Zustand. Es bietet Reset, Permalink-, JSON- und TypeScript-Copy sowie JSON-Download. Es ist vollständig ausblendbar und per Cmd/Ctrl+Shift+D wiederherstellbar beziehungsweise umschaltbar. Tastaturfokus und Reduced Motion werden berücksichtigt. URL-State verwendet nur den Parameter `fd` und erhält vorhandene Parameter.

## DOM-Inspector (V1)

Expand Down
8 changes: 5 additions & 3 deletions fixture/smoke.html
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,8 @@
panel.dispatchEvent(new PointerEvent('pointerdown', { bubbles: true, clientX: panelRect.left + 20, clientY: panelRect.top + 20, pointerId: 7 }));
panel.dispatchEvent(new PointerEvent('pointermove', { bubbles: true, clientX: 1, clientY: panelRect.top + 80, pointerId: 7 }));
panel.dispatchEvent(new PointerEvent('pointerup', { bubbles: true, clientX: 1, clientY: panelRect.top + 80, pointerId: 7 }));
const edgeSnap = panel.style.left === '0px' && panel.getBoundingClientRect().top >= 0;
const snappedRect = panel.getBoundingClientRect();
const edgeSnap = snappedRect.left === 0 && snappedRect.top >= 0 && snappedRect.left !== panelRect.left;

const running = document.createElement('video'); const paused = document.createElement('video');
document.body.append(running, paused); const runningBefore = { currentTime: running.currentTime, paused: running.paused }; const pausedBefore = { currentTime: paused.currentTime, paused: paused.paused };
Expand All @@ -193,8 +194,9 @@
const restoredMotion = getComputedStyle(motion).animationPlayState !== 'paused' && getComputedStyle(motion).transitionProperty !== 'none' && !shadow.querySelector('style[data-fd-freeze]') && !document.querySelector('style[data-fd-freeze]');
const videoState = frozenVideoState && running.paused === runningBefore.paused && running.currentTime === runningBefore.currentTime && paused.paused === pausedBefore.paused && paused.currentTime === pausedBefore.currentTime;
running.remove(); paused.remove();
panel.style.left = '9999px'; panel.style.top = '9999px'; window.dispatchEvent(new Event('resize'));
const resizeClamped = panel.getBoundingClientRect().right <= innerWidth && panel.getBoundingClientRect().bottom <= innerHeight;
element.style.left = '9999px'; element.style.top = '9999px'; window.dispatchEvent(new Event('resize'));
const resizedRect = panel.getBoundingClientRect();
const resizeClamped = resizedRect.right <= innerWidth && resizedRect.bottom <= innerHeight && resizedRect.left >= 0 && resizedRect.top >= 0;
const pickForReload = (target) => {
root.querySelector('[data-action="pick"]').click();
target.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true }));
Expand Down
15 changes: 10 additions & 5 deletions src/element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {
} from './core.js';

const styles = `
:host { all: initial; position: fixed; inset: auto 12px 12px auto; z-index: 2147483647; color: #e9edf2; font: 12px/1.3 ui-monospace, SFMono-Regular, monospace; }
:host { all: initial; display: block; position: fixed; inset: auto 12px 12px auto; z-index: 2147483647; color: #e9edf2; font: 12px/1.3 ui-monospace, SFMono-Regular, monospace; }
* { box-sizing: border-box; }
.panel { width: min(360px, calc(100vw - 24px)); max-height: min(760px, 70vh, calc(100vh - 24px)); overflow: auto; background: #17191c; border: 1px solid #454a51; border-radius: 6px; box-shadow: 0 5px 24px #0008; }
.bar { display: flex; align-items: center; gap: 6px; padding: 5px 7px; background: #22262a; position: sticky; top: 0; } .tabs { display:flex; gap:2px; padding:4px 7px; border-bottom:1px solid #353a40; } .tabs button { flex:1; }
Expand Down Expand Up @@ -119,7 +119,9 @@ export class FoundationDevtoolsElement extends HTMLElement {
const proposedTop = endEvent ? rect.top + endEvent.clientY - start.clientY : current.top;
const left = Math.abs(proposedLeft) <= edge ? 0 : Math.abs(innerWidth - (proposedLeft + current.width)) <= edge ? innerWidth - current.width : proposedLeft;
const top = Math.abs(proposedTop) <= edge ? 0 : Math.abs(innerHeight - (proposedTop + current.height)) <= edge ? innerHeight - current.height : proposedTop;
this.setPanelPosition(left, top); this.savePanelPosition(left, top);
this.setPanelPosition(left, top);
const snapped = this.panel!.getBoundingClientRect();
this.savePanelPosition(snapped.left, snapped.top);
};
this.panel!.addEventListener('pointermove', move); this.panel!.addEventListener('pointerup', end); this.panel!.addEventListener('pointercancel', end);
window.addEventListener('pointermove', move, true); window.addEventListener('pointerup', end, { once: true, capture: true }); window.addEventListener('pointercancel', end, { once: true, capture: true });
Expand Down Expand Up @@ -342,13 +344,16 @@ export class FoundationDevtoolsElement extends HTMLElement {
if (!this.panel) return;
const rect = this.panel.getBoundingClientRect();
const maxLeft = Math.max(0, innerWidth - rect.width); const maxTop = Math.max(0, innerHeight - rect.height);
this.panel.style.left = `${Math.max(0, Math.min(maxLeft, left))}px`; this.panel.style.top = `${Math.max(0, Math.min(maxTop, top))}px`;
this.panel.style.right = 'auto'; this.panel.style.bottom = 'auto';
this.style.left = `${Math.max(0, Math.min(maxLeft, left))}px`; this.style.top = `${Math.max(0, Math.min(maxTop, top))}px`;
this.style.right = 'auto'; this.style.bottom = 'auto';
}
private savePanelPosition(left: number, top: number): void { try { localStorage.setItem(`${this.storageKey}:position`, JSON.stringify({ left, top })); } catch {} }
private clampPanel = (): void => { if (!this.panel) return; const rect = this.panel.getBoundingClientRect(); this.setPanelPosition(rect.left, rect.top); };
private restorePosition(): void {
try { const value = JSON.parse(localStorage.getItem(`${this.storageKey}:position`) ?? 'null'); if (value && Number.isFinite(value.left) && Number.isFinite(value.top)) { this.panel!.style.left = `${Math.max(0, Math.min(innerWidth - this.panel!.offsetWidth, value.left))}px`; this.panel!.style.top = `${Math.max(0, Math.min(innerHeight - this.panel!.offsetHeight, value.top))}px`; this.panel!.style.right = 'auto'; this.panel!.style.bottom = 'auto'; } } catch {}
try {
const value = JSON.parse(localStorage.getItem(`${this.storageKey}:position`) ?? 'null');
if (value && Number.isFinite(value.left) && Number.isFinite(value.top)) this.setPanelPosition(value.left, value.top);
} catch {}
}
private restorePanelMode(): void {
let mode: 'open' | 'collapsed' = 'open';
Expand Down
Loading