@deepseek-ai/dsh-client-ui-dockkit 0.2.2-alpha.2 → 0.2.2-alpha.3
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 +2 -0
- package/README.zh.md +2 -0
- package/lib/index.js +31 -45
- package/lib/types/components/DockSurface.d.ts +7 -3
- package/lib/types/components/render.d.ts +7 -3
- package/package.json +5 -5
package/README.i18n.yaml
CHANGED
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
en: 718f52cfce426009
|
|
19
19
|
zh: e8282e2e3713d242
|
|
20
20
|
/deepseek-ai-dsh-client-ui-dockkit/embedding-it:
|
|
21
|
-
en:
|
|
22
|
-
zh:
|
|
21
|
+
en: 53bbabeb910c6f77
|
|
22
|
+
zh: 51fb4f8fb78cfd02
|
|
23
23
|
/deepseek-ai-dsh-client-ui-dockkit/interaction-rules-worth-keeping:
|
|
24
24
|
en: cf2d00ce2b7d5719
|
|
25
25
|
zh: 5510420f8872e23a
|
package/README.md
CHANGED
|
@@ -60,6 +60,8 @@ Everything host-specific arrives through props:
|
|
|
60
60
|
|
|
61
61
|
`dropZones="horizontal"` offers two half-pane hints; once budget or width forbids another split, the whole body accepts a move. A hint is a dashed card inset 8px inside its region, showing the zone's glyph and `labels.dropZone[zone]`; the preview layer covers all tab-body content, while the card under the pointer takes the accent and its neighbour stays a quiet outline. `minPaneFraction` sets the preview minimum, and `planResizeSplit` accepts the same minimum for the committed operation. The Sidebar uses 0.2 and enforces two panes in its own store. The generic engine retains its tree and other split directions. `hideSplitWhenBlocked` hides a blocked split control — pane budget spent or pane too narrow — instead of rendering it disabled; its default is false.
|
|
62
62
|
|
|
63
|
+
The split control wrapper exposes `data-dockkit-split-control` for embedder styling, independently of its element tag.
|
|
64
|
+
|
|
63
65
|
A tab's `kind` is an opaque string. Seeded tabs are factories (`DockControllerOptions`), so what a fresh pane contains is the embedder's decision, not this package's. Content identity is the pair (`kind`, `contentId`): `findContentTab(state, contentId, kind?)` finds the tab showing it anywhere and `findPaneContentTab(state, paneId, contentId, kind?)` within one pane, and `planOpenContent` focuses that tab instead of opening another unless told `revealIfOpened: false`; an explicit `index` seats a new tab at a strip slot rather than at the end.
|
|
64
66
|
|
|
65
67
|
`DockLayout`, used by the Sidebar, keeps each tab in a stable DOM cell across selection, pane moves and floating. It accepts one docked pane or two horizontal panes; CSS Grid resolves their widths. `keepMounted(tab)` retains visited bodies and `active` controls Session visibility without reparenting content.
|
package/README.zh.md
CHANGED
|
@@ -60,6 +60,8 @@ kind: "package-reference"
|
|
|
60
60
|
|
|
61
61
|
`dropZones="horizontal"` 提供左右两个半区提示;预算或宽度不允许再拆时,正文整格接收移动。提示是一张内缩 8px 的虚线卡片,显示该落区的图形和 `labels.dropZone[zone]`;预览层覆盖全部 tab 正文,指针所在的卡片取强调色,另一张保持安静的轮廓。`minPaneFraction` 控制预览的最小比例,`planResizeSplit` 接受相同最小值以约束提交;Sidebar使用0.2并在自己的store限制两格。通用引擎仍保留原有树与其它分割方向。 `hideSplitWhenBlocked` 在分栏被阻止时(窗格预算已满或格太窄)直接隐藏分栏控件而不是渲染禁用态,默认值为 false。
|
|
62
62
|
|
|
63
|
+
分栏控件的包裹元素通过 `data-dockkit-split-control` 提供宿主样式入口,不依赖具体元素标签。
|
|
64
|
+
|
|
63
65
|
tab 的 `kind` 是不透明字符串。种子 tab 是工厂(`DockControllerOptions`),因此新格里放什么由嵌入方决定,与本包无关。内容身份是二元组(`kind`、`contentId`):`findContentTab(state, contentId, kind?)` 在任意位置找到展示它的 tab,`findPaneContentTab(state, paneId, contentId, kind?)` 在一个格内找;`planOpenContent` 会聚焦该 tab 而非再开一个,除非被告知 `revealIfOpened: false`;显式的 `index` 把新 tab 放到 tab 条的某个位置而非末尾。
|
|
64
66
|
|
|
65
67
|
Sidebar 使用的 `DockLayout` 在选中项变化、跨格移动与浮动期间,把每个 tab 保留在稳定的 DOM 容器中。它接受一个停靠格或左右两个格,由 CSS Grid 计算宽度。`keepMounted(tab)` 保留已访问正文,`active` 控制 Session 可见性,不改变内容的父子关系。
|
package/lib/index.js
CHANGED
|
@@ -2461,30 +2461,6 @@ function TabTitle({ children }) {
|
|
|
2461
2461
|
//#endregion
|
|
2462
2462
|
//#region lib/types/components/TabPanel.js
|
|
2463
2463
|
/**
|
|
2464
|
-
* One pane: its tab strip (drag source, drop target, split control) and the
|
|
2465
|
-
* active tab's body with the dock preview overlay. Presentational; every gesture
|
|
2466
|
-
* leaves through `PaneCallbacks`, and the body itself comes from `renderTab`.
|
|
2467
|
-
*
|
|
2468
|
-
* A chip is a capsule carrying one control, its close, shown over its right
|
|
2469
|
-
* end while the chip is active, hovered, or focused; the context menu
|
|
2470
|
-
* (secondary press) carries the same close plus whatever the embedder appends.
|
|
2471
|
-
* A middle click anywhere on the chip, including its close control, closes
|
|
2472
|
-
* without selecting the tab, unless another mouse button is still held.
|
|
2473
|
-
* The embedder's `canCloseTab`
|
|
2474
|
-
* governs all close routes. A pane's lone chip whose close is withheld draws
|
|
2475
|
-
* quiet — no capsule, no hover fill — since there is nothing to select against
|
|
2476
|
-
* and nothing to do to it.
|
|
2477
|
-
* Between neighbouring chips sits a slot: a fixed-width box drawing a
|
|
2478
|
-
* hairline, blank beside the active chip, and the drop caret when a drag
|
|
2479
|
-
* targets that index, so a caret never widens the row; the two end slots
|
|
2480
|
-
* exist only while targeted. The chips sit in their own box, the strip's one
|
|
2481
|
-
* shrinking part: in a narrow pane their titles fade at the clipped edge down
|
|
2482
|
-
* to the chip's floor and then the chips scroll there, keeping the active one
|
|
2483
|
-
* in view, so the add control after them (drawn while the embedder's
|
|
2484
|
-
* `canAddTab` allows), the pane's split control, and the embedder's chrome keep
|
|
2485
|
-
* their width and their place at the strip's end.
|
|
2486
|
-
*/
|
|
2487
|
-
/**
|
|
2488
2464
|
* The ic_ds_panel_left_outline_16 frame alone: its outer and inner rounded
|
|
2489
2465
|
* rectangles as one even-odd ring, without the divider. The glyphs below draw
|
|
2490
2466
|
* inside it so they read as siblings of the panel controls beside them.
|
|
@@ -2735,6 +2711,20 @@ function TabStrip({ state, pane, callbacks, offsets }) {
|
|
|
2735
2711
|
const selected = tabId === pane.activeTabId;
|
|
2736
2712
|
const closable = callbacks.canCloseTab(tabId);
|
|
2737
2713
|
const quiet = !closable && pane.tabs.length === 1;
|
|
2714
|
+
const onKeyDown = (event) => {
|
|
2715
|
+
if (event.target !== event.currentTarget) return;
|
|
2716
|
+
if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey || event.nativeEvent.isComposing) return;
|
|
2717
|
+
const next = chipToFocus(event.key, pane.tabs, tabId);
|
|
2718
|
+
if (next !== void 0) {
|
|
2719
|
+
event.preventDefault();
|
|
2720
|
+
focusChip(next);
|
|
2721
|
+
return;
|
|
2722
|
+
}
|
|
2723
|
+
if (selects(event.key)) {
|
|
2724
|
+
event.preventDefault();
|
|
2725
|
+
activate(tabId);
|
|
2726
|
+
}
|
|
2727
|
+
};
|
|
2738
2728
|
return jsxs(Fragment$1, { children: [(index > 0 || stripIndex === index) && jsx("div", {
|
|
2739
2729
|
className: clsx(css.slot, stripIndex === index && css.slotCaret),
|
|
2740
2730
|
"data-dockkit-caret": stripIndex === index ? index : void 0
|
|
@@ -2766,32 +2756,25 @@ function TabStrip({ state, pane, callbacks, offsets }) {
|
|
|
2766
2756
|
event.stopPropagation();
|
|
2767
2757
|
activate(tabId);
|
|
2768
2758
|
},
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
focusChip(next);
|
|
2776
|
-
return;
|
|
2777
|
-
}
|
|
2778
|
-
if (selects(event.key)) {
|
|
2759
|
+
...callbacks.getTabTriggerProps?.(tab, pane.id, {
|
|
2760
|
+
onKeyDown,
|
|
2761
|
+
tabIndex: selected ? 0 : -1
|
|
2762
|
+
}) ?? {
|
|
2763
|
+
onKeyDown,
|
|
2764
|
+
onContextMenu: (event) => {
|
|
2779
2765
|
event.preventDefault();
|
|
2780
|
-
|
|
2766
|
+
event.stopPropagation();
|
|
2767
|
+
const anchor = event.currentTarget;
|
|
2768
|
+
setMenu((current) => current?.tabId === tabId ? void 0 : {
|
|
2769
|
+
tabId,
|
|
2770
|
+
anchor
|
|
2771
|
+
});
|
|
2781
2772
|
}
|
|
2782
2773
|
},
|
|
2783
|
-
onContextMenu: (event) => {
|
|
2784
|
-
event.preventDefault();
|
|
2785
|
-
const anchor = event.currentTarget;
|
|
2786
|
-
setMenu((current) => current?.tabId === tabId ? void 0 : {
|
|
2787
|
-
tabId,
|
|
2788
|
-
anchor
|
|
2789
|
-
});
|
|
2790
|
-
},
|
|
2791
2774
|
children: [
|
|
2792
2775
|
jsx(TabTitle, { children: callbacks.renderTabTitle?.(tab) ?? tab.title }),
|
|
2793
2776
|
closable && jsx(Tooltip, {
|
|
2794
|
-
disabled: menu !== void 0,
|
|
2777
|
+
disabled: menu !== void 0 || callbacks.tabMenuOpen === true,
|
|
2795
2778
|
label: callbacks.labels.closeTab,
|
|
2796
2779
|
shortcutKeys: callbacks.labels.closeTabKeys,
|
|
2797
2780
|
side: "bottom",
|
|
@@ -2860,6 +2843,7 @@ function TabStrip({ state, pane, callbacks, offsets }) {
|
|
|
2860
2843
|
delayMs: 500,
|
|
2861
2844
|
openOnClick: block !== void 0,
|
|
2862
2845
|
children: jsx("span", {
|
|
2846
|
+
"data-dockkit-split-control": true,
|
|
2863
2847
|
tabIndex: block === void 0 ? void 0 : 0,
|
|
2864
2848
|
"aria-label": block === void 0 ? void 0 : splitBlockedTitle(callbacks.labels, block),
|
|
2865
2849
|
onClick: (event) => {
|
|
@@ -3690,7 +3674,7 @@ function sameSizes(a, b) {
|
|
|
3690
3674
|
});
|
|
3691
3675
|
}
|
|
3692
3676
|
/** The split tree and the gestures over it. */
|
|
3693
|
-
function Surface({ state, canSplit, canAddTab, canCloseTab, intents, labels, renderTab, renderTabTitle, renderTabMenuItems, chrome, onRoom, draw, dropZones = "edges", minPaneFraction = MIN_PANE_FRACTION, hideSplitWhenBlocked = false }) {
|
|
3677
|
+
function Surface({ state, canSplit, canAddTab, canCloseTab, intents, labels, renderTab, renderTabTitle, renderTabMenuItems, getTabTriggerProps, tabMenuOpen, chrome, onRoom, draw, dropZones = "edges", minPaneFraction = MIN_PANE_FRACTION, hideSplitWhenBlocked = false }) {
|
|
3694
3678
|
const surface = useRef(null);
|
|
3695
3679
|
const [preview, setPreview] = useState(NO_PREVIEW);
|
|
3696
3680
|
const [fits, setFits] = useState(NO_FITS);
|
|
@@ -3811,6 +3795,8 @@ function Surface({ state, canSplit, canAddTab, canCloseTab, intents, labels, ren
|
|
|
3811
3795
|
renderTab,
|
|
3812
3796
|
renderTabTitle,
|
|
3813
3797
|
renderTabMenuItems,
|
|
3798
|
+
getTabTriggerProps,
|
|
3799
|
+
tabMenuOpen,
|
|
3814
3800
|
chromePaneId: topRightPaneId(state),
|
|
3815
3801
|
chrome
|
|
3816
3802
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { ReactNode } from 'react';
|
|
1
|
+
import type { ReactNode, HTMLAttributes } from 'react';
|
|
2
2
|
import type { DockIntents, DockLabels, TabMenuExtras, TabRenderer } from '../contract/adapter.ts';
|
|
3
|
-
import type { LayoutState, PaneId, TabId } from '../contract/types.ts';
|
|
3
|
+
import type { LayoutState, PaneId, TabId, TabRecord } from '../contract/types.ts';
|
|
4
4
|
import type { HalvesFit } from '../engine/geometry.ts';
|
|
5
5
|
import { type TabRetention } from './TabLayout.tsx';
|
|
6
6
|
/** What the docked surface needs: the layout, its limits, and the outward contracts. */
|
|
@@ -41,7 +41,11 @@ export interface DockSurfaceProps {
|
|
|
41
41
|
* slot, and nothing outside that embedder is expected to supply it.
|
|
42
42
|
*/
|
|
43
43
|
readonly renderTabTitle?: TabRenderer;
|
|
44
|
-
/**
|
|
44
|
+
/** Whether the embedder popup is preparing or visible; suppresses tab tooltips. */
|
|
45
|
+
readonly tabMenuOpen?: boolean | undefined;
|
|
46
|
+
/** Override the kit popup; the embedder owns rendering and dismissal. */
|
|
47
|
+
readonly getTabTriggerProps?: ((tab: TabRecord, paneId: PaneId, handlers?: Pick<HTMLAttributes<HTMLElement>, 'onContextMenu' | 'onKeyDown' | 'tabIndex'>) => Pick<HTMLAttributes<HTMLElement>, 'onContextMenu' | 'onKeyDown' | 'tabIndex'>) | undefined;
|
|
48
|
+
/** Extra rows for the kit popup; ignored when getTabTriggerProps is supplied. */
|
|
45
49
|
readonly renderTabMenuItems?: TabMenuExtras;
|
|
46
50
|
/**
|
|
47
51
|
* Surface-wide controls, drawn at the far end of the top-right pane's tab
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
* Prop shares the kit's own components pass among themselves. These are internal
|
|
3
3
|
* to the package — the outward contracts are in `adapter.ts`.
|
|
4
4
|
*/
|
|
5
|
-
import type { PointerEvent as ReactPointerEvent, ReactNode } from 'react';
|
|
5
|
+
import type { PointerEvent as ReactPointerEvent, ReactNode, HTMLAttributes } from 'react';
|
|
6
6
|
import type { DockLabels, TabMenuExtras, TabRenderer } from '../contract/adapter.ts';
|
|
7
|
-
import type { PaneId, SplitId, TabId } from '../contract/types.ts';
|
|
7
|
+
import type { PaneId, SplitId, TabId, TabRecord } from '../contract/types.ts';
|
|
8
8
|
import type { DropTarget } from '../engine/geometry.ts';
|
|
9
9
|
/** Why a pane's split control is disabled: the pane budget, or too little width for two halves. */
|
|
10
10
|
export type SplitBlock = 'budget' | 'width';
|
|
@@ -37,7 +37,11 @@ export interface PaneCallbacks {
|
|
|
37
37
|
readonly renderTab: TabRenderer;
|
|
38
38
|
/** A chip's or panel header's title content; absent means the record's `title` text. */
|
|
39
39
|
readonly renderTabTitle: TabRenderer | undefined;
|
|
40
|
-
/**
|
|
40
|
+
/** Whether the embedder popup is preparing or visible; suppresses tab tooltips. */
|
|
41
|
+
readonly tabMenuOpen?: boolean | undefined;
|
|
42
|
+
/** Override the kit popup; the embedder owns rendering and dismissal. */
|
|
43
|
+
readonly getTabTriggerProps?: ((tab: TabRecord, paneId: PaneId, handlers?: Pick<HTMLAttributes<HTMLElement>, 'onContextMenu' | 'onKeyDown' | 'tabIndex'>) => Pick<HTMLAttributes<HTMLElement>, 'onContextMenu' | 'onKeyDown' | 'tabIndex'>) | undefined;
|
|
44
|
+
/** Extra rows for the kit popup; ignored when getTabTriggerProps is supplied. */
|
|
41
45
|
readonly renderTabMenuItems: TabMenuExtras | undefined;
|
|
42
46
|
/** The pane whose strip hosts the embedder's surface-wide controls. */
|
|
43
47
|
readonly chromePaneId: PaneId;
|
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.2-alpha.
|
|
4
|
+
"version": "0.2.2-alpha.3",
|
|
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.6-alpha.
|
|
27
|
-
"@deepseek-ai/dsh-brand": "0.2.2-alpha.
|
|
28
|
-
"@deepseek-ai/dsh-client-ui-primitives": "0.2.2-alpha.
|
|
26
|
+
"@deepseek-ai/cordis": "~4.0.6-alpha.2",
|
|
27
|
+
"@deepseek-ai/dsh-brand": "0.2.2-alpha.3",
|
|
28
|
+
"@deepseek-ai/dsh-client-ui-primitives": "0.2.2-alpha.3",
|
|
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.6-alpha.
|
|
40
|
+
"@deepseek-ai/cordis": "~4.0.6-alpha.2"
|
|
41
41
|
}
|
|
42
42
|
}
|