@takazudo/zdtp 0.4.9 → 0.4.11

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.
@@ -1,7 +1,7 @@
1
1
  import { jsx as y, jsxs as K, Fragment as kt } from "preact/jsx-runtime";
2
2
  import { useEffect as P, useState as Y, useRef as O, useMemo as J, useCallback as X } from "preact/hooks";
3
- import { b as ft, p as wt, u as ht, a as Ne, A as bt, Z as gt } from "./index-t74PT2zd.js";
4
- import { g as vt, m as j } from "./panel-config-BNLlUc_r.js";
3
+ import { b as ft, p as wt, u as ht, a as Ne, A as bt, Z as gt } from "./index-BeYH-tJD.js";
4
+ import { g as vt, m as j } from "./panel-config-7Xg59uKj.js";
5
5
  const xt = (e, o) => {
6
6
  const t = new Array(e.length + o.length);
7
7
  for (let r = 0; r < e.length; r++)
package/dist/index.d.ts CHANGED
@@ -35,6 +35,20 @@
35
35
  */
36
36
  import './styles/panel.css';
37
37
  import { type PanelConfig } from './config/panel-config';
38
+ /**
39
+ * Test-only: snapshot of the mounted-shell slot registry (prefix -> ordinal).
40
+ * A copy, so a test cannot mutate the live registry through it.
41
+ *
42
+ * Prefixed `__` to make it clear this is internal/test surface, not a
43
+ * documented public API.
44
+ */
45
+ export declare function __mountedSpawnSlotsForTests(): ReadonlyMap<string, number>;
46
+ /**
47
+ * Test-only: drop every registered slot. Unlike the bindings reset this has
48
+ * no listeners to drain — the registry holds plain numbers — so clearing the
49
+ * map is the whole teardown.
50
+ */
51
+ export declare function __resetSpawnSlotsForTests(): void;
38
52
  export { configurePanel, setPanelColorPresets } from './config/panel-config';
39
53
  export type { PanelConfig, PanelInstanceHandle, ApplySink } from './config/panel-config';
40
54
  /**
package/dist/index.js CHANGED
@@ -1,37 +1,39 @@
1
1
  import "preact/jsx-runtime";
2
2
  import "preact";
3
- import { S as i, c as t, d as n, _ as l, e as d, f as _, g, h as p, i as P, j as m, k as A, l as C, m as u, n as c, o as f, q as K, r as M, s as T, t as v, v as S, w as E, x as h } from "./index-t74PT2zd.js";
4
- import { Z as D, U as k, v as y, u as F, X as H } from "./tweak-state-Dti6XMoQ.js";
5
- import { c as b, s as w } from "./panel-config-BNLlUc_r.js";
6
- import "./autoload-state-CFmRjtD-.js";
3
+ import { S as t, c as i, d as n, _ as l, e as d, f as _, g as p, h as g, i as m, j as P, k as u, l as A, m as C, n as S, o as T, q as c, r as f, s as K, t as M, v, w as E, x as F, y as h, z as w } from "./index-BeYH-tJD.js";
4
+ import { Z as y, U as D, v as k, u as H, X as L } from "./tweak-state-DRKV1uYj.js";
5
+ import { c as O, s as V } from "./panel-config-7Xg59uKj.js";
6
+ import "./autoload-state-CTDDBxI8.js";
7
7
  export {
8
- i as SCHEMA_V1,
9
- t as SCHEMA_V2,
8
+ t as SCHEMA_V1,
9
+ i as SCHEMA_V2,
10
10
  n as SCHEMA_V3,
11
- D as ZDTP_LEGACY_TYPOGRAPHY_RENAME_MAP,
12
- l as __panelConfigForTest,
13
- d as __reapplyFromStorageForTests,
14
- _ as __resetInstanceBindingsForTests,
15
- b as configurePanel,
16
- g as disableAutoload,
17
- k as emptyOverrides,
18
- p as enableAutoload,
19
- y as getClusterDefaultMode,
20
- P as hideDesignTokenPanel,
21
- m as isColorKind,
22
- A as isContentKind,
23
- C as isCursorKind,
24
- u as isLengthKind,
11
+ y as ZDTP_LEGACY_TYPOGRAPHY_RENAME_MAP,
12
+ l as __mountedSpawnSlotsForTests,
13
+ d as __panelConfigForTest,
14
+ _ as __reapplyFromStorageForTests,
15
+ p as __resetInstanceBindingsForTests,
16
+ g as __resetSpawnSlotsForTests,
17
+ O as configurePanel,
18
+ m as disableAutoload,
19
+ D as emptyOverrides,
20
+ P as enableAutoload,
21
+ k as getClusterDefaultMode,
22
+ u as hideDesignTokenPanel,
23
+ A as isColorKind,
24
+ C as isContentKind,
25
+ S as isCursorKind,
26
+ T as isLengthKind,
25
27
  c as isMaskImageKind,
26
28
  f as isNumberKind,
27
29
  K as isSelectKind,
28
30
  M as isTextKind,
29
- T as reapplyPersistedOverrides,
30
- F as resolvePerModeLiteral,
31
- H as resolveSemanticPreviewColor,
32
- v as setLifecycleAdapter,
33
- w as setPanelColorPresets,
34
- S as shouldAutoload,
35
- E as showDesignTokenPanel,
36
- h as toggleDesignPanel
31
+ v as reapplyPersistedOverrides,
32
+ H as resolvePerModeLiteral,
33
+ L as resolveSemanticPreviewColor,
34
+ E as setLifecycleAdapter,
35
+ V as setPanelColorPresets,
36
+ F as shouldAutoload,
37
+ h as showDesignTokenPanel,
38
+ w as toggleDesignPanel
37
39
  };
@@ -336,10 +336,10 @@ const _ = {
336
336
  // No bundled apply endpoint / routing — hosts wire their own.
337
337
  applyEndpoint: void 0,
338
338
  applyRouting: void 0
339
- }, R = /* @__PURE__ */ Symbol.for("@takazudo/zdtp:singleton");
339
+ }, O = /* @__PURE__ */ Symbol.for("@takazudo/zdtp:singleton");
340
340
  function m() {
341
341
  const e = globalThis;
342
- let t = e[R];
342
+ let t = e[O];
343
343
  return t || (t = {
344
344
  instances: /* @__PURE__ */ new Map(),
345
345
  defaultPrefix: null,
@@ -347,7 +347,7 @@ function m() {
347
347
  pendingPostConfigureHooks: [],
348
348
  lifecycleHooks: {},
349
349
  colorSchemeOwners: /* @__PURE__ */ new Set()
350
- }, e[R] = t), t;
350
+ }, e[O] = t), t;
351
351
  }
352
352
  function F(e) {
353
353
  return {
@@ -499,19 +499,19 @@ function Ce(e, t) {
499
499
  function Pe(e) {
500
500
  return `${e.exportFilenameBase}.json`;
501
501
  }
502
- const O = /* @__PURE__ */ Symbol.for("@takazudo/zdtp:global-alias-marker");
502
+ const R = /* @__PURE__ */ Symbol.for("@takazudo/zdtp:global-alias-marker");
503
503
  function Ee(e) {
504
504
  if (typeof window > "u") return;
505
505
  const t = window, n = t.zdtp;
506
506
  if (n !== void 0) {
507
- if ((typeof n == "object" || typeof n == "function") && n !== null && n[O] === !0) return;
507
+ if ((typeof n == "object" || typeof n == "function") && n !== null && n[R] === !0) return;
508
508
  console.warn(
509
509
  "[design-token-panel] window.zdtp already exists and was not installed by this package. Skipping the zdtp.show() / zdtp.hide() / zdtp.toggle() global alias to avoid clobbering it. Use window[consoleNamespace].* or the configurePanel(cfg) handle instead."
510
510
  );
511
511
  return;
512
512
  }
513
513
  const i = { ...e };
514
- i[O] = !0, t.zdtp = i;
514
+ i[R] = !0, t.zdtp = i;
515
515
  }
516
516
  function ve(e) {
517
517
  if (e === null || typeof e != "object" || Array.isArray(e))
@@ -565,6 +565,10 @@ function ve(e) {
565
565
  );
566
566
  }
567
567
  }
568
+ if (t.autoRememberOnOpen !== void 0 && typeof t.autoRememberOnOpen != "boolean")
569
+ throw new Error(
570
+ `[design-token-panel] PanelConfig.autoRememberOnOpen must be a boolean when set (got ${typeof t.autoRememberOnOpen})`
571
+ );
568
572
  if (t.legacyIdRenameMap !== void 0) {
569
573
  if (t.legacyIdRenameMap === null || typeof t.legacyIdRenameMap != "object" || Array.isArray(t.legacyIdRenameMap))
570
574
  throw new Error("[design-token-panel] PanelConfig.legacyIdRenameMap must be a plain object");
@@ -926,17 +930,17 @@ export {
926
930
  be as K,
927
931
  oe as _,
928
932
  he as a,
929
- fe as b,
933
+ ve as b,
930
934
  ee as c,
931
- ce as d,
932
- ge as e,
933
- ve as f,
935
+ ue as d,
936
+ pe as e,
937
+ de as f,
934
938
  D as g,
935
- ue as h,
939
+ fe as h,
936
940
  Ee as i,
937
- pe as j,
938
- de as k,
939
- we as l,
941
+ we as j,
942
+ ge as k,
943
+ ce as l,
940
944
  Ce as m,
941
945
  se as n,
942
946
  le as o,
package/dist/panel.d.ts CHANGED
@@ -10,9 +10,16 @@ import { type PanelConfig } from './config/panel-config';
10
10
  * distinct sync events, and render distinct manifests, never cross-talking.
11
11
  * Omitted (e.g. a direct test render) → the active/default instance, preserving
12
12
  * the historical single-panel behaviour.
13
+ *
14
+ * `spawnOrdinal` is this shell's slot in the mounted-shell registry (#584),
15
+ * handed down by the adapter at `render(...)` time. It cascades the FIRST-OPEN
16
+ * position of concurrently mounted instances apart (#585) so a second panel
17
+ * stops landing exactly on top of the first; a persisted position ignores it.
18
+ * Omitted → 0, i.e. no offset.
13
19
  */
14
20
  interface DesignTokenTweakPanelProps {
15
21
  instanceConfig?: PanelConfig;
22
+ spawnOrdinal?: number;
16
23
  }
17
- export default function DesignTokenTweakPanel({ instanceConfig: instanceConfigProp, }?: DesignTokenTweakPanelProps): import("preact").JSX.Element;
24
+ export default function DesignTokenTweakPanel({ instanceConfig: instanceConfigProp, spawnOrdinal, }?: DesignTokenTweakPanelProps): import("preact").JSX.Element;
18
25
  export type { TweakState } from './state/tweak-state';
@@ -3,31 +3,66 @@
3
3
  *
4
4
  * ## Flag semantics
5
5
  *
6
- * `${storagePrefix}:autoload` (written as `'1'` when armed, `'0'` or absent
7
- * when not) is the owner-mode flag. It means:
6
+ * `${storagePrefix}:autoload` is the owner-mode flag. It means:
8
7
  * "This browser visited the site as the site owner — autoload the
9
8
  * design-token panel on every subsequent page visit."
10
9
  *
10
+ * The stored value carries the flag's **provenance** — how the browser came to
11
+ * be in owner mode:
12
+ *
13
+ * - `'1'` — **explicit**: the owner deliberately armed owner mode. Written only
14
+ * by `enableAutoload()` (via `setAutoload(cfg, true)`).
15
+ * - `'auto'` — **auto-remembered**: something merely opened the panel once.
16
+ * Written by `rememberAutoload()` from the five auto-remember sites —
17
+ * `showInstance` / `toggleInstance` / the header-button + window-event
18
+ * handler in `index.tsx`, and `showDesignPanel` / the toggle handler in
19
+ * `astro/host-adapter.ts`.
20
+ * - `'0'`, absent, or any other value — **not in owner mode**. Written by
21
+ * `setAutoload(cfg, false)`; `clearAutoload()` removes the key outright.
22
+ *
23
+ * The split exists so a **downstream host** can discriminate the two
24
+ * populations — e.g. keep an `=== '1'` probe and stop eagerly fetching the
25
+ * panel bundle for a visitor who clicked a panel button once months ago.
26
+ *
27
+ * **zdtp's own gates honour BOTH values.** `shouldAutoload()` is `true` for
28
+ * `'1'` and `'auto'` alike, so an owner who reached owner mode by opening the
29
+ * panel still gets the auto-reload this module documents. Making zdtp's own
30
+ * gate ignore `'auto'` would be a silent behaviour regression for every
31
+ * existing user — the discrimination lives in the *stored value*, not in
32
+ * zdtp's behaviour.
33
+ *
34
+ * Auto-remember never **downgrades** an existing `'1'`: an owner who armed
35
+ * explicitly and then opens the panel keeps the explicit provenance.
36
+ *
37
+ * ### Legacy values are forward-looking only
38
+ *
39
+ * Browsers that auto-remembered BEFORE the provenance value existed already
40
+ * hold `'1'`, and no migration can recover a provenance that was never stored.
41
+ * They therefore read as explicit owners forever. A downstream host must not
42
+ * expect an `=== '1'` probe to immediately shed its whole legacy population —
43
+ * the discrimination only applies to writes made from this version onward.
44
+ *
11
45
  * ## General-visitor vs owner behavior
12
46
  *
13
- * - **General visitor** (flag absent or `!== '1'`): the panel bundle is NOT
14
- * eagerly fetched. Gate #1 (`shouldAutoload`) returns false, so no bundle
15
- * request fires on page load. The panel remains entirely invisible.
16
- * - **Owner** (flag === `'1'`): Gate #1 fires, the host-adapter fetches the
17
- * bundle eagerly, and Gate #2 (`reapplyFromStorage` in `index.tsx`) mounts
18
- * the Preact shell CLOSED so the element-path inspector is available even
19
- * while the panel UI is hidden.
47
+ * - **General visitor** (flag absent, `'0'`, or any unrecognised value): the
48
+ * panel bundle is NOT eagerly fetched. Gate #1 (`shouldAutoload`) returns
49
+ * false, so no bundle request fires on page load. The panel remains entirely
50
+ * invisible.
51
+ * - **Owner** (flag `'1'` or `'auto'`): Gate #1 fires, the host-adapter fetches
52
+ * the bundle eagerly, and Gate #2 (`reapplyFromStorage` in `index.tsx`)
53
+ * mounts the Preact shell CLOSED so the element-path inspector is available
54
+ * even while the panel UI is hidden.
20
55
  *
21
56
  * ## enableAutoload() / disableAutoload() contract (implemented by S2 #419)
22
57
  *
23
58
  * `enableAutoload()` (console API, wired by S2):
24
- * 1. Sets `:autoload = '1'`.
59
+ * 1. Sets `:autoload = '1'` (explicit provenance).
25
60
  * 2. Sets `-elpath-enabled = '1'` once (arms the alt+click inspector).
26
61
  * 3. Loads the panel bundle (if not already loaded).
27
62
  * 4. Mounts the Preact shell CLOSED via `hideInstance`.
28
63
  *
29
64
  * `disableAutoload()` (console API, wired by S2):
30
- * 1. Clears `:autoload`.
65
+ * 1. Clears `:autoload` (removes the key, whichever value it held).
31
66
  * 2. Clears `:visible`.
32
67
  * 3. Clears `-elpath-enabled`.
33
68
  * 4. Clears the open-state key (`getOpenKey(cfg)` from `state/tweak-state`).
@@ -36,9 +71,17 @@
36
71
  * ## Auto-remember
37
72
  *
38
73
  * Any action that shows the panel (console `showDesignPanel()`, the header-
39
- * button open event, or the `showInstance` path in `index.tsx`) MUST also
40
- * write `:autoload = '1'`. Once an owner opens the panel the flag is set so
41
- * subsequent page loads reload it automatically. (Wired by S2 / S3.)
74
+ * button open event, or the `showInstance` path in `index.tsx`) MUST also call
75
+ * `rememberAutoload(cfg)`, which writes `:autoload = 'auto'`. Once the panel
76
+ * has been opened the flag is set so subsequent page loads reload it
77
+ * automatically. (Wired by S2 / S3.)
78
+ *
79
+ * A host can opt out of this entirely by setting `PanelConfig.autoRememberOnOpen
80
+ * = false` — `rememberAutoload` then becomes a no-op, so opening the panel
81
+ * never persists owner-mode. This exists for a public docs site that wants a
82
+ * visible panel button for every visitor without arming owner-mode for
83
+ * whoever clicks it. `enableAutoload()` (which writes `'1'` via `setAutoload`,
84
+ * not this function) is unaffected either way.
42
85
  *
43
86
  * ## Element-path coupling
44
87
  *
@@ -64,26 +107,53 @@
64
107
  * are persisted yet.
65
108
  */
66
109
  import type { PanelConfig } from '../config/panel-config';
110
+ /** Stored `:autoload` value meaning "the owner armed owner mode deliberately". */
111
+ export declare const AUTOLOAD_EXPLICIT = "1";
112
+ /** Stored `:autoload` value meaning "owner mode was inferred from a panel open". */
113
+ export declare const AUTOLOAD_AUTO_REMEMBERED = "auto";
67
114
  /**
68
- * Return `true` iff this browser has the owner-autoload flag set.
115
+ * Return `true` iff this browser has the owner-autoload flag set, regardless of
116
+ * how it got there.
69
117
  *
70
118
  * SSR-safe (returns `false` when `window` is not available) and quota-
71
119
  * tolerant (returns `false` on any storage error). Reads exactly
72
- * `${cfg.storagePrefix}:autoload` and matches against the literal string
73
- * `'1'`; any other stored value (including `'0'` or an absent key) is `false`.
120
+ * `${cfg.storagePrefix}:autoload` and matches `'1'` (explicit) or `'auto'`
121
+ * (auto-remembered); any other stored value — including `'0'` and an absent
122
+ * key — is `false`.
74
123
  */
75
124
  export declare function shouldAutoload(cfg: PanelConfig): boolean;
76
125
  /**
77
- * Write the owner-autoload flag. Pass `true` to arm autoload (`'1'`), `false`
78
- * to disarm (`'0'`). SSR-safe and quota-tolerant — errors are swallowed
79
- * silently so this never throws in restricted storage contexts.
126
+ * Write the owner-autoload flag with EXPLICIT provenance. Pass `true` to arm
127
+ * autoload (`'1'`), `false` to disarm (`'0'`). SSR-safe and quota-tolerant —
128
+ * errors are swallowed silently so this never throws in restricted storage
129
+ * contexts.
130
+ *
131
+ * Reserved for the deliberate `enableAutoload()` path; auto-remember call sites
132
+ * use `rememberAutoload` so the two populations stay distinguishable in storage.
80
133
  *
81
134
  * Prefer `clearAutoload` when you want to fully remove the key (e.g. on
82
135
  * `disableAutoload`) rather than leave a `'0'` sentinel.
83
136
  */
84
137
  export declare function setAutoload(cfg: PanelConfig, on: boolean): void;
85
138
  /**
86
- * Remove the owner-autoload flag from storage entirely.
139
+ * Arm the owner-autoload flag with AUTO-REMEMBERED provenance (`'auto'`).
140
+ *
141
+ * Called from every auto-remember site — any action that merely opens the panel.
142
+ * An existing explicit `'1'` is left untouched: an owner who armed owner mode
143
+ * deliberately must not demote themselves by opening the panel.
144
+ *
145
+ * No-op when `cfg.autoRememberOnOpen === false` — see that field's doc for the
146
+ * public-site use case. The gate lives HERE (not at each call site) so a
147
+ * future auto-remember site inherits it automatically instead of needing its
148
+ * own opt-out check. `enableAutoload()` calls `setAutoload`, not this
149
+ * function, so it is never subject to this gate.
150
+ *
151
+ * SSR-safe and quota-tolerant.
152
+ */
153
+ export declare function rememberAutoload(cfg: PanelConfig): void;
154
+ /**
155
+ * Remove the owner-autoload flag from storage entirely, whichever provenance
156
+ * value it held.
87
157
  *
88
158
  * Called by `disableAutoload()` (S2) as part of the full owner-mode teardown.
89
159
  * SSR-safe and quota-tolerant.
@@ -104,16 +104,36 @@ export declare const DEFAULT_POSITION: PanelPosition;
104
104
  /**
105
105
  * Compute a viewport-centered default panel position for first-open behaviour.
106
106
  *
107
- * The panel CSS-sizes itself up to 1200×800 but caps at 80% of the viewport,
108
- * so we mirror the same min/0.8x rule here. The resulting `top` / `left`
109
- * place the panel at the geometric center of the viewport.
107
+ * Delegates to `defaultGeometry()` so the position is centered against the
108
+ * panel's *actual* clamped default size rather than an independently derived
109
+ * one — see that function for why the two must not be computed separately.
110
+ *
111
+ * `spawnOrdinal` cascades concurrently-mounted instances apart; ordinal 0 (the
112
+ * default, and the only ordinal a single-panel host ever sees) is exactly the
113
+ * centered position. `size`, when given, is the rectangle to center — pass the
114
+ * size the panel will actually render at rather than letting the default size
115
+ * be assumed.
110
116
  *
111
117
  * Falls back to the static `DEFAULT_POSITION` when `window` is undefined
112
118
  * (e.g. SSR / node test setup without jsdom). Real browsers + jsdom-backed
113
119
  * tests get the centered position.
114
120
  */
115
- export declare function defaultPosition(): PanelPosition;
116
- export declare function loadPosition(cfg?: PanelConfig): PanelPosition;
121
+ export declare function defaultPosition(spawnOrdinal?: number, size?: PanelSize): PanelPosition;
122
+ /**
123
+ * Read this instance's persisted position, falling back to the cascaded
124
+ * first-open default.
125
+ *
126
+ * `spawnOrdinal` is applied ONLY to the fallback. A stored position is an
127
+ * explicit user preference — a panel the user dragged somewhere reopens
128
+ * exactly there, never nudged by however many siblings happen to be mounted.
129
+ *
130
+ * `size` is the size the caller will actually render at (i.e. `loadSize()`'s
131
+ * result). Pass it so the fallback is centered and contained against THAT
132
+ * rectangle: an instance with a persisted size but no persisted position
133
+ * would otherwise be centered as if it were the default width and spawn
134
+ * partly off-screen.
135
+ */
136
+ export declare function loadPosition(cfg?: PanelConfig, spawnOrdinal?: number, size?: PanelSize): PanelPosition;
117
137
  export declare function savePosition(pos: PanelPosition, cfg?: PanelConfig): void;
118
138
  /** Keep at least VISIBLE_MIN px of the panel on-screen so the user can grab it back. */
119
139
  export declare const VISIBLE_MIN = 60;
@@ -141,6 +161,8 @@ export declare const DEFAULT_SIZE: PanelSize;
141
161
  * result respects the MIN_PANEL_* floor and the viewport cap. The floor only
142
162
  * bites on phone-width viewports (e.g. 375px → 0.8*375 = 300, raised to the
143
163
  * 320 min); on normal viewports the clamp is a no-op.
164
+ *
165
+ * Delegates to `defaultGeometry()` — the single place the rule lives.
144
166
  */
145
167
  export declare function defaultSize(): PanelSize;
146
168
  /**
@@ -149,6 +171,52 @@ export declare function defaultSize(): PanelSize;
149
171
  * from rendering off-screen when reopened on a 1080p laptop.
150
172
  */
151
173
  export declare function clampSize(width: number, height: number): PanelSize;
174
+ /** Per-ordinal cascade step, in px, applied to both axes on a fresh spawn. */
175
+ export declare const SPAWN_CASCADE_STEP = 24;
176
+ /** Position + size of a panel, as one coherent rectangle. */
177
+ export interface PanelGeometry extends PanelPosition, PanelSize {
178
+ }
179
+ /**
180
+ * Compute the coherent first-open geometry: the clamped default size, plus a
181
+ * position that centers *that* rectangle in the viewport.
182
+ *
183
+ * Position and size used to be derived independently — `defaultPosition()`
184
+ * centered a phantom `min(1200, 0.8 * vw)` panel while `defaultSize()` raised
185
+ * that same value to the `MIN_PANEL_WIDTH` floor. On a 320px viewport the two
186
+ * disagreed by 32px (left 32 + width 320 = 352) and the panel spawned partly
187
+ * off-screen; `clampPosition()` did not catch it because it is a permissive
188
+ * drag-recovery clamp that only guarantees `VISIBLE_MIN` px stays grabbable.
189
+ * Computing the size first and centering against it keeps them in lockstep,
190
+ * and is the reason `defaultPosition()` / `defaultSize()` are thin wrappers
191
+ * rather than independent implementations.
192
+ *
193
+ * `spawnOrdinal` (from the mount layer's slot registry) cascades a second and
194
+ * third concurrently-mounted instance away from the first — see
195
+ * `SPAWN_CASCADE_STEP` and `clampSpawnPosition`. Ordinal 0 takes no offset, so
196
+ * a single-panel host is byte-identical to the pre-cascade behaviour.
197
+ *
198
+ * The ordinal travels mount layer -> geometry, never the reverse: this module
199
+ * must not import `index.tsx` (epic #582, decision 4).
200
+ *
201
+ * Falls back to the static SSR constants when `window` is undefined.
202
+ */
203
+ export declare function defaultGeometry(spawnOrdinal?: number, sizeOverride?: PanelSize): PanelGeometry;
204
+ /**
205
+ * Clamp a FRESH-SPAWN position so the whole panel sits inside the viewport:
206
+ * `left ∈ [0, max(0, innerWidth - panelWidth)]`, `top` likewise.
207
+ *
208
+ * Deliberately NOT `clampPosition()`. That one is the drag-recovery clamp and
209
+ * is permissive on purpose — it lets a panel the user dragged hang off the
210
+ * edge so long as `VISIBLE_MIN` px stay grabbable. Spawn containment is a
211
+ * stricter, separate rule (epic #582, decision 2), so it gets its own clamp
212
+ * rather than tightening a clamp other behaviour depends on.
213
+ *
214
+ * Containment beats distinctness: on a viewport with no spare room the upper
215
+ * bound collapses to 0 and the cascade degrades — reduced first, dropped
216
+ * entirely when there is nothing left. Two instances may then coincide. That
217
+ * is the documented trade-off; a panel spawned off-screen is worse.
218
+ */
219
+ export declare function clampSpawnPosition(top: number, left: number, panelWidth: number, panelHeight: number): PanelPosition;
152
220
  export declare function loadSize(cfg?: PanelConfig): PanelSize;
153
221
  export declare function saveSize(size: PanelSize, cfg?: PanelConfig): void;
154
222
  /**
package/dist/testing.js CHANGED
@@ -1,8 +1,8 @@
1
- import { _ as r, c as _, h as i, j as n, k as g, b as R, a as p } from "./panel-config-BNLlUc_r.js";
2
- import { a as y, b as O, l as P } from "./tweak-state-Dti6XMoQ.js";
1
+ import { _ as r, c as _, d as i, e as n, f as g, h as R, a as p } from "./panel-config-7Xg59uKj.js";
2
+ import { a as l, b as y, l as O } from "./tweak-state-DRKV1uYj.js";
3
3
  import { F as K, G as E, a as S, S as u } from "./manifest-DCReQE0k.js";
4
- async function s(a, e) {
5
- await a.fill(e), await a.dispatchEvent("input");
4
+ async function s(e, a) {
5
+ await e.fill(a), await e.dispatchEvent("input");
6
6
  }
7
7
  export {
8
8
  K as FONT_GROUP_ORDER,
@@ -11,9 +11,9 @@ export {
11
11
  u as SIZE_GROUP_ORDER,
12
12
  r as __resetPanelConfigForTests,
13
13
  _ as configurePanel,
14
- y as getStorageKeyV1,
15
- O as getStorageKeyV2,
16
- P as loadPersistedState,
14
+ l as getStorageKeyV1,
15
+ y as getStorageKeyV2,
16
+ O as loadPersistedState,
17
17
  s as setPanelInputValue,
18
18
  i as storageKey_open,
19
19
  n as storageKey_position,