@deepseek-ai/dsh-client-ui-dockkit 0.1.5-alpha.1 → 0.1.5-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.
- package/README.i18n.yaml +2 -2
- package/README.md +9 -9
- package/README.zh.md +9 -9
- package/lib/components/dockkit.module.css +405 -99
- package/lib/index.js +370 -161
- package/lib/types/components/DockSurface.d.ts +12 -4
- package/lib/types/components/FloatLayer.d.ts +4 -2
- package/lib/types/components/TabMenu.d.ts +2 -1
- package/lib/types/components/TabTitle.d.ts +6 -0
- package/lib/types/components/measure.d.ts +5 -1
- package/lib/types/components/render.d.ts +4 -2
- package/lib/types/contract/adapter.d.ts +6 -2
- package/lib/types/engine/geometry.d.ts +21 -8
- package/lib/types/engine/planner.d.ts +6 -3
- package/package.json +5 -7
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
2
|
import type { DockIntents, DockLabels, TabMenuExtras, TabRenderer } from '../contract/adapter.ts';
|
|
3
|
-
import type { LayoutState, PaneId } from '../contract/types.ts';
|
|
3
|
+
import type { LayoutState, PaneId, TabId } from '../contract/types.ts';
|
|
4
4
|
import type { HalvesFit } from '../engine/geometry.ts';
|
|
5
5
|
/** What the docked surface needs: the layout, its limits, and the outward contracts. */
|
|
6
6
|
export interface DockSurfaceProps {
|
|
@@ -11,8 +11,8 @@ export interface DockSurfaceProps {
|
|
|
11
11
|
* split control disabled with `labels.splitPaneNarrow` (see README).
|
|
12
12
|
*/
|
|
13
13
|
readonly canSplit: boolean;
|
|
14
|
-
/** Hide
|
|
15
|
-
readonly
|
|
14
|
+
/** Hide a blocked split control — pane budget spent or pane too narrow — instead of rendering it disabled; defaults to false. */
|
|
15
|
+
readonly hideSplitWhenBlocked?: boolean;
|
|
16
16
|
/** Body drop geometry: all edge bands, or left/right halves with whole-pane moves once splitting is unavailable. */
|
|
17
17
|
readonly dropZones?: 'edges' | 'horizontal';
|
|
18
18
|
/** Smallest share a divider may leave a pane; defaults to the kit's fraction. */
|
|
@@ -23,6 +23,14 @@ export interface DockSurfaceProps {
|
|
|
23
23
|
* end controls where they are and the chips as the only shrinking part.
|
|
24
24
|
*/
|
|
25
25
|
readonly canAddTab?: (paneId: PaneId) => boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Whether a tab draws its close control and its menu's close item. Called
|
|
28
|
+
* per rendered chip on every render; omit to keep every tab closable.
|
|
29
|
+
* `false` removes both routes without moving the chip: the close control
|
|
30
|
+
* paints over the title's end rather than beside it, so the chip is the same
|
|
31
|
+
* width either way. The menu still opens and carries the embedder's items.
|
|
32
|
+
*/
|
|
33
|
+
readonly canCloseTab?: (tabId: TabId) => boolean;
|
|
26
34
|
readonly intents: DockIntents;
|
|
27
35
|
readonly labels: DockLabels;
|
|
28
36
|
readonly renderTab: TabRenderer;
|
|
@@ -48,5 +56,5 @@ export interface DockSurfaceProps {
|
|
|
48
56
|
readonly onRoom?: (fits: ReadonlyMap<PaneId, HalvesFit>) => void;
|
|
49
57
|
}
|
|
50
58
|
/** The split tree and the gestures over it. */
|
|
51
|
-
export declare function DockSurface({ state, canSplit, canAddTab, intents, labels, renderTab, renderTabTitle, renderTabMenuItems, chrome, onRoom, dropZones, minPaneFraction,
|
|
59
|
+
export declare function DockSurface({ state, canSplit, canAddTab, canCloseTab, intents, labels, renderTab, renderTabTitle, renderTabMenuItems, chrome, onRoom, dropZones, minPaneFraction, hideSplitWhenBlocked, }: DockSurfaceProps): ReactNode;
|
|
52
60
|
//# sourceMappingURL=DockSurface.d.ts.map
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
2
|
import type { DockIntents, DockLabels, TabRenderer } from '../contract/adapter.ts';
|
|
3
|
-
import type { LayoutState } from '../contract/types.ts';
|
|
3
|
+
import type { LayoutState, TabId } from '../contract/types.ts';
|
|
4
4
|
/** The layout whose `floats` this layer draws. */
|
|
5
5
|
export interface FloatLayerProps {
|
|
6
6
|
readonly state: LayoutState;
|
|
7
7
|
readonly intents: DockIntents;
|
|
8
8
|
readonly labels: DockLabels;
|
|
9
9
|
readonly renderTab: TabRenderer;
|
|
10
|
+
/** Whether a floating tab offers its close control; defaults to true. Called per tab on every render. */
|
|
11
|
+
readonly canCloseTab?: (tabId: TabId) => boolean;
|
|
10
12
|
/** The panel header's title content; omit to show the record's `title` text (see `DockSurfaceProps`). */
|
|
11
13
|
readonly renderTabTitle?: TabRenderer;
|
|
12
14
|
}
|
|
13
15
|
/** Every floating panel, in z order. */
|
|
14
|
-
export declare function FloatLayer({ state, intents, labels, renderTab, renderTabTitle }: FloatLayerProps): ReactNode;
|
|
16
|
+
export declare function FloatLayer({ state, intents, labels, renderTab, renderTabTitle, canCloseTab }: FloatLayerProps): ReactNode;
|
|
15
17
|
//# sourceMappingURL=FloatLayer.d.ts.map
|
|
@@ -5,7 +5,8 @@ export interface TabMenuProps {
|
|
|
5
5
|
readonly labels: DockLabels;
|
|
6
6
|
/** The control that opened the menu; the menu hangs below its left edge. */
|
|
7
7
|
readonly anchor: HTMLElement;
|
|
8
|
-
|
|
8
|
+
/** Close the tab; `undefined` removes the kit's item, leaving the extras only. */
|
|
9
|
+
readonly onClose: (() => void) | undefined;
|
|
9
10
|
/** Dismiss without acting. */
|
|
10
11
|
readonly onDismiss: () => void;
|
|
11
12
|
/** Embedder items, rendered after the kit's own; absent means none. */
|
|
@@ -15,9 +15,13 @@ export declare function paneElements(root: HTMLElement): readonly (readonly [Pan
|
|
|
15
15
|
/**
|
|
16
16
|
* Measure every docked pane under `root`.
|
|
17
17
|
* @param root - the docked surface's element.
|
|
18
|
+
* @param splitHiddenWhenBlocked - whether the embedder hides blocked split
|
|
19
|
+
* controls (`hideSplitWhenBlocked`); the room rule then leaves the control's
|
|
20
|
+
* footprint out of each strip's fixed part, so the reading cannot flip with
|
|
21
|
+
* the control's visibility (see `PaneMeasure.splitControlWidth`).
|
|
18
22
|
* @returns each pane's fit, keyed by pane id.
|
|
19
23
|
*/
|
|
20
|
-
export declare function measurePaneFits(root: HTMLElement): ReadonlyMap<PaneId, HalvesFit>;
|
|
24
|
+
export declare function measurePaneFits(root: HTMLElement, splitHiddenWhenBlocked?: boolean): ReadonlyMap<PaneId, HalvesFit>;
|
|
21
25
|
/**
|
|
22
26
|
* One pane's latest reading. A pane the map does not name has not been
|
|
23
27
|
* measured and fits: the rule only blocks on a positive reading.
|
|
@@ -21,10 +21,12 @@ export interface PaneCallbacks {
|
|
|
21
21
|
readonly onDividerPressed: (splitId: SplitId, index: number, event: ReactPointerEvent<HTMLElement>) => void;
|
|
22
22
|
/** Why a pane cannot split right now, or `undefined` while it can. */
|
|
23
23
|
readonly splitBlock: (paneId: PaneId) => SplitBlock | undefined;
|
|
24
|
-
/** Hide
|
|
25
|
-
readonly
|
|
24
|
+
/** Hide blocked split controls instead of rendering them disabled. */
|
|
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. */
|
|
29
|
+
readonly canCloseTab: (tabId: TabId) => boolean;
|
|
28
30
|
/** Live drop preview, or `undefined` while nothing is being dragged. */
|
|
29
31
|
readonly dropTarget: DropTarget | undefined;
|
|
30
32
|
/** Show both horizontal landing regions while a body split is being targeted. */
|
|
@@ -30,6 +30,8 @@ export interface DockLabels {
|
|
|
30
30
|
readonly dockFloat: string;
|
|
31
31
|
/** Close a floating panel. */
|
|
32
32
|
readonly closeFloat: string;
|
|
33
|
+
/** The drop hint's caption for each body zone a dragged tab can land on. */
|
|
34
|
+
readonly dropZone: Readonly<Record<DockZone, string>>;
|
|
33
35
|
}
|
|
34
36
|
/**
|
|
35
37
|
* Renders one tab's body. The embedder dispatches on `tab.kind`, which is the
|
|
@@ -42,10 +44,12 @@ export type TabRenderer = (tab: TabRecord) => ReactNode;
|
|
|
42
44
|
*
|
|
43
45
|
* The kit's own item is the close gesture; anything that means something about
|
|
44
46
|
* the tab's content comes from here. An item that acts MUST call `dismiss`,
|
|
45
|
-
* because the menu closes on its own items only.
|
|
47
|
+
* because the menu closes on its own items only. Every rendered item MUST
|
|
48
|
+
* carry `role="menuitem"`: the kit probes for that role to dismiss a menu
|
|
49
|
+
* that would paint empty, so items without it count as an empty menu.
|
|
46
50
|
* @param tab - the tab whose menu is open.
|
|
47
51
|
* @param dismiss - close the menu without acting.
|
|
48
|
-
* @returns
|
|
52
|
+
* @returns extra actions with ARIA menuitem, menuitemcheckbox, or menuitemradio roles, or nothing.
|
|
49
53
|
*/
|
|
50
54
|
export type TabMenuExtras = (tab: TabRecord, dismiss: () => void) => ReactNode;
|
|
51
55
|
/**
|
|
@@ -60,6 +60,17 @@ export interface PaneMeasure {
|
|
|
60
60
|
readonly chipsWidth: number;
|
|
61
61
|
/** Width of the fill: free space, not a control. */
|
|
62
62
|
readonly fillWidth: number;
|
|
63
|
+
/**
|
|
64
|
+
* Footprint of the rendered split control (its width plus the strip's gap)
|
|
65
|
+
* for embedders that hide blocked split controls: a half too narrow to
|
|
66
|
+
* split hides its own control, so the rule leaves the footprint out of the
|
|
67
|
+
* fixed part. Leaving it out is also what keeps the reading stable — the
|
|
68
|
+
* control hiding sheds the same footprint from the strip, and a reading
|
|
69
|
+
* that counted it would flip with the control's visibility and re-render
|
|
70
|
+
* forever. Absent or 0 keeps the control in the fixed part, for embedders
|
|
71
|
+
* that render a blocked control disabled.
|
|
72
|
+
*/
|
|
73
|
+
readonly splitControlWidth?: number;
|
|
63
74
|
}
|
|
64
75
|
/** Pixel minimums the room rule holds each half to. */
|
|
65
76
|
export interface SplitMinimums {
|
|
@@ -67,15 +78,16 @@ export interface SplitMinimums {
|
|
|
67
78
|
readonly divider: number;
|
|
68
79
|
/** One chip at its minimum: the smallest strip that still names a tab. */
|
|
69
80
|
readonly chip: number;
|
|
70
|
-
/** The smallest body under a strip: one secondary text line inside the body's
|
|
81
|
+
/** The smallest body under a strip: one secondary text line inside 12px of the body's own insets. */
|
|
71
82
|
readonly body: number;
|
|
72
83
|
}
|
|
73
84
|
/**
|
|
74
85
|
* The minimums where no computed style can be read, mirroring
|
|
75
|
-
* `dockkit.module.css`: `.splitRow > .divider`
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
86
|
+
* `dockkit.module.css`: `.splitRow > .divider` takes no layout width (its
|
|
87
|
+
* hairline is painted over the seam); `.tab` is 80px of content plus
|
|
88
|
+
* 10px + 10px of padding (content-box), 100px; 12px above and below one 13px
|
|
89
|
+
* secondary line at 1.6 line-height — the inset a body draws for itself, as
|
|
90
|
+
* `.empty` does — is 45px, held to 48px.
|
|
79
91
|
*/
|
|
80
92
|
export declare const SPLIT_MINIMUMS: SplitMinimums;
|
|
81
93
|
/** Whether a pane's two halves after an equal split would each still work. */
|
|
@@ -87,9 +99,10 @@ export interface HalvesFit {
|
|
|
87
99
|
}
|
|
88
100
|
/**
|
|
89
101
|
* The room rule. After an equal split each half must hold what cannot shrink:
|
|
90
|
-
* horizontally the strip's fixed part — its width minus the chip box
|
|
91
|
-
* fill, which is the padding, the gaps, and every
|
|
92
|
-
* plus one chip at its minimum; vertically
|
|
102
|
+
* horizontally the strip's fixed part — its width minus the chip box, the
|
|
103
|
+
* fill, and `splitControlWidth`, which is the padding, the gaps, and every
|
|
104
|
+
* control a half would still draw — plus one chip at its minimum; vertically
|
|
105
|
+
* the strip plus a minimum body. The
|
|
93
106
|
* borders are what the pane's box exceeds the strip's by. An unmeasured pane
|
|
94
107
|
* (no layout, as under jsdom) fits: the rule only blocks on a positive reading.
|
|
95
108
|
* @param measure - the pane's rectangles.
|
|
@@ -128,16 +128,19 @@ export declare function planPlaceTab(state: LayoutState, tabId: TabId, toPaneId:
|
|
|
128
128
|
/**
|
|
129
129
|
* Resolve a tab release on a pane body: the centre moves the tab in, an edge
|
|
130
130
|
* splits the pane and seats the tab in the new half. A pane's only tab released
|
|
131
|
-
* on that pane changes nothing
|
|
132
|
-
*
|
|
131
|
+
* on that pane's centre changes nothing; released on its edge it splits, and
|
|
132
|
+
* the factory's tab backfills the pane the drag would otherwise empty — without
|
|
133
|
+
* a factory that release also changes nothing, since the split would empty the
|
|
134
|
+
* pane and seat the tab beside where it already was.
|
|
133
135
|
* @param state - current layout.
|
|
134
136
|
* @param mint - id source for a pane an edge release creates.
|
|
135
137
|
* @param tabId - the dragged tab.
|
|
136
138
|
* @param targetPaneId - pane under the pointer.
|
|
137
139
|
* @param zone - dock region the pointer released in.
|
|
140
|
+
* @param makeTab - builds the tab that backfills a pane its only tab splits away from.
|
|
138
141
|
* @returns the operations, or none when the release changes nothing.
|
|
139
142
|
*/
|
|
140
|
-
export declare function planDropTab(state: LayoutState, mint: Mint, tabId: TabId, targetPaneId: PaneId, zone: DockZone): readonly LayoutOp[];
|
|
143
|
+
export declare function planDropTab(state: LayoutState, mint: Mint, tabId: TabId, targetPaneId: PaneId, zone: DockZone, makeTab?: TabFactory): readonly LayoutOp[];
|
|
141
144
|
/**
|
|
142
145
|
* Take a tab out into a floating panel.
|
|
143
146
|
* @param state - current layout.
|
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.1.5-alpha.
|
|
4
|
+
"version": "0.1.5-alpha.2",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -22,18 +22,16 @@
|
|
|
22
22
|
"./package.json": "./package.json"
|
|
23
23
|
},
|
|
24
24
|
"license": "MIT",
|
|
25
|
-
"dependencies": {
|
|
26
|
-
"clsx": "^2.0.0",
|
|
27
|
-
"react": "^18.2.0",
|
|
28
|
-
"react-dom": "^18.2.0"
|
|
29
|
-
},
|
|
30
25
|
"devDependencies": {
|
|
31
26
|
"@testing-library/react": "^16.1.0",
|
|
32
27
|
"@types/react": "~18.3.1",
|
|
33
28
|
"@types/react-dom": "~18.3.0",
|
|
34
29
|
"react-dom": "^18.2.0",
|
|
30
|
+
"react": "^18.2.0",
|
|
31
|
+
"clsx": "^2.0.0",
|
|
32
|
+
"@deepseek-ai/dsh-brand": "^0.1.5-alpha.2",
|
|
35
33
|
"@deepseek-ai/cordis": "^4.0.2",
|
|
36
|
-
"@deepseek-ai/dsh-
|
|
34
|
+
"@deepseek-ai/dsh-client-ui-primitives": "^0.1.5-alpha.2"
|
|
37
35
|
},
|
|
38
36
|
"files": [
|
|
39
37
|
"lib/index.js",
|