@deepseek-ai/dsh-client-ui-dockkit 0.2.1-rc.4 → 0.2.2-alpha.2

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.
@@ -25,9 +25,9 @@ export interface DockSurfaceProps {
25
25
  */
26
26
  readonly canAddTab?: (paneId: PaneId) => boolean;
27
27
  /**
28
- * Whether a tab draws its close control and its menu's close item. Called
28
+ * Whether a tab may close via its close control, menu item, or middle click. Called
29
29
  * per rendered chip on every render; omit to keep every tab closable.
30
- * `false` removes both routes without moving the chip: the close control
30
+ * `false` blocks these routes without moving the chip: the close control
31
31
  * paints over the title's end rather than beside it, so the chip is the same
32
32
  * width either way. The menu still opens and carries the embedder's items.
33
33
  */
@@ -1,4 +1,4 @@
1
- import type { PointerEvent as ReactPointerEvent, ReactNode } from 'react';
1
+ import type { CSSProperties, PointerEvent as ReactPointerEvent, ReactNode } from 'react';
2
2
  import type { DockIntents, DockLabels, TabRenderer } from '../contract/adapter.ts';
3
3
  import type { FloatRect, LayoutState, PaneId, TabId, TabRecord } from '../contract/types.ts';
4
4
  /** The layout whose `floats` this layer draws. */
@@ -12,11 +12,25 @@ export interface FloatLayerProps {
12
12
  /** The panel header's title content; omit to show the record's `title` text (see `DockSurfaceProps`). */
13
13
  readonly renderTabTitle?: TabRenderer;
14
14
  }
15
+ /**
16
+ * Inline position of a floating panel. A gesture or return draws it exactly at
17
+ * `rect`. At rest the panel only publishes `rect` to the `.float` rule, which
18
+ * clamps it into the viewport and below the caption floor, so a stale viewport
19
+ * reading in `useFloatGestures` still leaves the panel inside.
20
+ * @param rect - the rectangle to draw.
21
+ * @param lifted - whether a gesture or return is drawing the panel.
22
+ * @returns the panel's inline position and size.
23
+ */
24
+ export declare function floatStyle(rect: FloatRect, lifted: boolean): CSSProperties;
15
25
  /**
16
26
  * Shared move/resize gestures; changing layout mode never owns the content DOM.
27
+ * Panels draw at their stored rectangle projected into the viewport, so a
28
+ * shrinking window pushes them in without recording anything. A move past an
29
+ * edge draws with resistance; its release records the legal rectangle and the
30
+ * panel springs there from where it was drawn.
17
31
  * @param state - committed layout and float stacking order.
18
32
  * @param intents - gesture settlements.
19
- * @returns the current preview and focus/gesture callbacks.
33
+ * @returns the current preview, the rectangle to draw per panel, and focus/gesture callbacks.
20
34
  */
21
35
  export declare function useFloatGestures(state: LayoutState, intents: DockIntents): {
22
36
  preview: {
@@ -25,6 +39,7 @@ export declare function useFloatGestures(state: LayoutState, intents: DockIntent
25
39
  } | undefined;
26
40
  raise: (paneId: PaneId) => void;
27
41
  drag: (mode: "move" | "resize", paneId: PaneId, event: ReactPointerEvent<HTMLElement>) => void;
42
+ rectOf: (paneId: PaneId, stored: FloatRect) => FloatRect;
28
43
  };
29
44
  /**
30
45
  * Header-only controls, usable above either retained or visibility-mounted bodies.
@@ -0,0 +1,9 @@
1
+ import type { ReactNode } from 'react';
2
+ import type { TabRenderer } from '../contract/adapter.ts';
3
+ import type { TabRecord } from '../contract/types.ts';
4
+ /** One tab's body, re-rendered only when `renderTab` or `tab` is a new object. */
5
+ export declare const TabBody: import("react").MemoExoticComponent<({ tab, renderTab }: {
6
+ readonly tab: TabRecord;
7
+ readonly renderTab: TabRenderer;
8
+ }) => ReactNode>;
9
+ //# sourceMappingURL=TabBody.d.ts.map
@@ -1,5 +1,5 @@
1
1
  import type { ReactNode } from 'react';
2
- import type { LayoutState, PaneNode } from '../contract/types.ts';
2
+ import type { LayoutState, PaneId, PaneNode } from '../contract/types.ts';
3
3
  import type { PaneCallbacks } from './render.ts';
4
4
  /** A pane and the live layout it reads its tabs from. */
5
5
  export interface TabPanelProps {
@@ -7,10 +7,21 @@ export interface TabPanelProps {
7
7
  readonly pane: PaneNode;
8
8
  readonly callbacks: PaneCallbacks;
9
9
  }
10
- /** @param props - pane state and gestures. @returns its tab strip without a content container. */
11
- export declare function TabStrip({ state, pane, callbacks }: TabPanelProps): ReactNode;
10
+ /** A tab strip and where it reads and records its pane's chip-box offset. */
11
+ interface TabStripProps extends TabPanelProps {
12
+ /**
13
+ * Chip-box offsets by pane, shared by the strips that replace one another
14
+ * as a pane's selected tab changes. Keys are valid within one layout only,
15
+ * and entries outlive their panes. Omitted where no strip continues from
16
+ * another's position.
17
+ */
18
+ readonly offsets?: Map<PaneId, number>;
19
+ }
20
+ /** @param props - pane state, gestures and shared offsets. @returns its tab strip without a content container. */
21
+ export declare function TabStrip({ state, pane, callbacks, offsets }: TabStripProps): ReactNode;
12
22
  /** @param props - target pane and drag preview. @returns body-local drop feedback, or nothing. */
13
23
  export declare function PaneDropHints({ pane, callbacks }: Pick<TabPanelProps, 'pane' | 'callbacks'>): ReactNode;
14
24
  /** @param props - pane state and gestures. @returns one pane in the recursive, visibility-mounted layout. */
15
25
  export declare function TabPanel({ state, pane, callbacks }: TabPanelProps): ReactNode;
26
+ export {};
16
27
  //# sourceMappingURL=TabPanel.d.ts.map
@@ -25,7 +25,7 @@ export interface PaneCallbacks {
25
25
  readonly hideSplitWhenBlocked?: boolean;
26
26
  /** Whether a pane's strip draws the add control. */
27
27
  readonly canAddTab: (paneId: PaneId) => boolean;
28
- /** Whether a tab draws its close control and its menu's close item. */
28
+ /** Whether a tab may close via its close control, menu item, or middle click. */
29
29
  readonly canCloseTab: (tabId: TabId) => boolean;
30
30
  /** Live drop preview, or `undefined` while nothing is being dragged. */
31
31
  readonly dropTarget: DropTarget | undefined;
@@ -43,7 +43,11 @@ export interface DockLabels {
43
43
  }
44
44
  /**
45
45
  * Renders one tab's body. The embedder dispatches on `tab.kind`, which is the
46
- * only place that string carries meaning.
46
+ * only place that string carries meaning. As `renderTab`, the kit calls it
47
+ * again only when the renderer or the tab record is a new object and reuses the
48
+ * previous body across its own re-renders, such as a gesture's frames: the body
49
+ * must follow from `tab` and the values the renderer captures, and any other
50
+ * input reaches it through a new renderer or the body's own hooks and context.
47
51
  */
48
52
  export type TabRenderer = (tab: TabRecord) => ReactNode;
49
53
  /**
@@ -151,6 +151,52 @@ export declare function movedRect(rect: FloatRect, dx: number, dy: number): Floa
151
151
  * @returns the resized rectangle; the origin is unchanged.
152
152
  */
153
153
  export declare function resizedRect(rect: FloatRect, dx: number, dy: number, min: Size): FloatRect;
154
+ /**
155
+ * The viewport region floating panels stay inside: `[0, width]` horizontally and
156
+ * `[top, height]` vertically, where `top` keeps the header clear of window chrome.
157
+ */
158
+ export interface FloatBounds {
159
+ readonly top: number;
160
+ readonly width: number;
161
+ readonly height: number;
162
+ }
163
+ /** How far past an edge the resistance lets a dragged panel travel, at most, in CSS pixels. */
164
+ export declare const FLOAT_RESISTANCE = 120;
165
+ /**
166
+ * The nearest rectangle that lies inside the bounds, per axis. A panel larger
167
+ * than the bounds on an axis takes the bounds' size on it, so its header
168
+ * controls and resize corner stay reachable.
169
+ * @param rect - any rectangle, possibly outside the bounds.
170
+ * @param bounds - the viewport region.
171
+ * @returns the rectangle moved inside the bounds, its size capped by them.
172
+ */
173
+ export declare function legalFloatRect(rect: FloatRect, bounds: FloatBounds): FloatRect;
174
+ /**
175
+ * Where a dragged panel draws when the pointer has taken it past an edge: the
176
+ * legal rectangle plus a resisted share of the overflow on each axis.
177
+ * @param desired - the rectangle the pointer travel asks for.
178
+ * @param bounds - the viewport region.
179
+ * @returns the drawn rectangle at the legal size; equal to `desired` while it is legal.
180
+ */
181
+ export declare function resistedRect(desired: FloatRect, bounds: FloatBounds): FloatRect;
182
+ /**
183
+ * The rectangle a drag must start from so that zero pointer travel draws
184
+ * `drawn`, the inverse of `resistedRect`: a press on a panel still outside the
185
+ * bounds picks it up where it is.
186
+ * @param drawn - where the panel is drawn now.
187
+ * @param bounds - the viewport region.
188
+ * @returns the start rectangle at the legal size; equal to `drawn` while it is legal.
189
+ */
190
+ export declare function unresistedRect(drawn: FloatRect, bounds: FloatBounds): FloatRect;
191
+ /**
192
+ * A resized rectangle whose bottom-right corner stays inside the bounds, never
193
+ * below the minimum size.
194
+ * @param rect - the resized rectangle; its origin may lie outside the bounds.
195
+ * @param bounds - the viewport region.
196
+ * @param min - smallest size the panel may take.
197
+ * @returns the rectangle with its size capped by the bounds.
198
+ */
199
+ export declare function boundedResize(rect: FloatRect, bounds: FloatBounds, min: Size): FloatRect;
154
200
  /**
155
201
  * Where a panel should appear when a tab is dropped outside the docked area.
156
202
  * @param x - drop point x.
@@ -0,0 +1,47 @@
1
+ /**
2
+ * The spring a floating panel follows back inside the viewport after a release
3
+ * past an edge. Pure and clock-free: the caller supplies each frame's elapsed
4
+ * time, so trajectories are deterministic for a given sequence of frames.
5
+ */
6
+ /** One axis of a spring: where it is and how fast it moves, in CSS pixels and pixels per second. */
7
+ export interface SpringAxis {
8
+ readonly position: number;
9
+ readonly velocity: number;
10
+ }
11
+ /** Fastest release velocity a return starts with, in pixels per second. */
12
+ export declare const SPRING_MAX_VELOCITY = 1500;
13
+ /** A return ends at its target after this long even if it is still moving. */
14
+ export declare const SPRING_DEADLINE_MS = 900;
15
+ /** A frame longer than this is clamped, so a slow frame cannot inject a jump. */
16
+ export declare const SPRING_MAX_FRAME_MS = 64;
17
+ /** A gap longer than this (sleep, a stalled tab) ends the return at its target instead of animating catch-up. */
18
+ export declare const SPRING_STALL_MS = 250;
19
+ /**
20
+ * Advance one axis by an elapsed time, in equal substeps no longer than `SUBSTEP`
21
+ * (semi-implicit Euler).
22
+ * @param axis - the axis state.
23
+ * @param target - the position the spring pulls toward.
24
+ * @param dtSeconds - elapsed time, already clamped by the caller.
25
+ * @returns the advanced state.
26
+ */
27
+ export declare function stepSpring(axis: SpringAxis, target: number, dtSeconds: number): SpringAxis;
28
+ /**
29
+ * The velocity an axis starts its return with. An axis already at its target
30
+ * keeps still. Outward speed is capped at `omega0 * (reach - |offset|)`: the
31
+ * spring carries a start offset `d` and speed `v` at most `d + 0.46 * v / omega0`
32
+ * from its target, so the whole return stays within `reach`.
33
+ * @param position - where the axis is drawn at release.
34
+ * @param target - the position the spring pulls toward.
35
+ * @param velocity - the drawn release velocity, in pixels per second.
36
+ * @param reach - the farthest the return may be from the target.
37
+ * @returns the starting velocity.
38
+ */
39
+ export declare function launchVelocity(position: number, target: number, velocity: number, reach: number): number;
40
+ /**
41
+ * Whether an axis has come to rest at its target.
42
+ * @param axis - the axis state.
43
+ * @param target - the spring's target.
44
+ * @returns true within `REST_DISTANCE` of the target and slower than `REST_SPEED`.
45
+ */
46
+ export declare function springSettled(axis: SpringAxis, target: number): boolean;
47
+ //# sourceMappingURL=spring.d.ts.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@deepseek-ai/dsh-client-ui-dockkit",
3
3
  "description": "Docking layout kit: split-tree engine with invertible operations, and the React components that render and drive it (zero cordis)",
4
- "version": "0.2.1-rc.4",
4
+ "version": "0.2.2-alpha.2",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -23,9 +23,9 @@
23
23
  },
24
24
  "license": "MIT",
25
25
  "devDependencies": {
26
- "@deepseek-ai/cordis": "~4.0.5",
27
- "@deepseek-ai/dsh-brand": "0.2.1-rc.4",
28
- "@deepseek-ai/dsh-client-ui-primitives": "0.2.1-rc.4",
26
+ "@deepseek-ai/cordis": "~4.0.6-alpha.1",
27
+ "@deepseek-ai/dsh-brand": "0.2.2-alpha.2",
28
+ "@deepseek-ai/dsh-client-ui-primitives": "0.2.2-alpha.2",
29
29
  "@testing-library/react": "^16.3.3",
30
30
  "react-dom": "^18.2.0",
31
31
  "react": "^18.2.0",
@@ -37,6 +37,6 @@
37
37
  "lib/types/**/*.d.ts"
38
38
  ],
39
39
  "peerDependencies": {
40
- "@deepseek-ai/cordis": "~4.0.5"
40
+ "@deepseek-ai/cordis": "~4.0.6-alpha.1"
41
41
  }
42
42
  }