@edv4h/usketch-plugin-dashboard 0.2.0

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.
Files changed (63) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +52 -0
  3. package/dist/config-ops.d.ts +48 -0
  4. package/dist/config-ops.d.ts.map +1 -0
  5. package/dist/config-ops.js +101 -0
  6. package/dist/config-ops.js.map +1 -0
  7. package/dist/dashboard-config-shape-def.d.ts +4 -0
  8. package/dist/dashboard-config-shape-def.d.ts.map +1 -0
  9. package/dist/dashboard-config-shape-def.js +33 -0
  10. package/dist/dashboard-config-shape-def.js.map +1 -0
  11. package/dist/dashboard-config-shape.d.ts +71 -0
  12. package/dist/dashboard-config-shape.d.ts.map +1 -0
  13. package/dist/dashboard-config-shape.js +51 -0
  14. package/dist/dashboard-config-shape.js.map +1 -0
  15. package/dist/dashboard-runtime.d.ts +23 -0
  16. package/dist/dashboard-runtime.d.ts.map +1 -0
  17. package/dist/dashboard-runtime.js +726 -0
  18. package/dist/dashboard-runtime.js.map +1 -0
  19. package/dist/dashboard-service.d.ts +76 -0
  20. package/dist/dashboard-service.d.ts.map +1 -0
  21. package/dist/dashboard-service.js +287 -0
  22. package/dist/dashboard-service.js.map +1 -0
  23. package/dist/drag-target-store.d.ts +11 -0
  24. package/dist/drag-target-store.d.ts.map +1 -0
  25. package/dist/drag-target-store.js +33 -0
  26. package/dist/drag-target-store.js.map +1 -0
  27. package/dist/grid-overlay.d.ts +16 -0
  28. package/dist/grid-overlay.d.ts.map +1 -0
  29. package/dist/grid-overlay.js +111 -0
  30. package/dist/grid-overlay.js.map +1 -0
  31. package/dist/grid.d.ts +110 -0
  32. package/dist/grid.d.ts.map +1 -0
  33. package/dist/grid.js +214 -0
  34. package/dist/grid.js.map +1 -0
  35. package/dist/index.d.ts +13 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +13 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/items.d.ts +25 -0
  40. package/dist/items.d.ts.map +1 -0
  41. package/dist/items.js +59 -0
  42. package/dist/items.js.map +1 -0
  43. package/dist/order.d.ts +10 -0
  44. package/dist/order.d.ts.map +1 -0
  45. package/dist/order.js +15 -0
  46. package/dist/order.js.map +1 -0
  47. package/dist/plugin.d.ts +12 -0
  48. package/dist/plugin.d.ts.map +1 -0
  49. package/dist/plugin.js +59 -0
  50. package/dist/plugin.js.map +1 -0
  51. package/dist/register-dashboard-hud.d.ts +5 -0
  52. package/dist/register-dashboard-hud.d.ts.map +1 -0
  53. package/dist/register-dashboard-hud.js +173 -0
  54. package/dist/register-dashboard-hud.js.map +1 -0
  55. package/dist/slide-animation.d.ts +10 -0
  56. package/dist/slide-animation.d.ts.map +1 -0
  57. package/dist/slide-animation.js +67 -0
  58. package/dist/slide-animation.js.map +1 -0
  59. package/dist/viewport-lock.d.ts +4 -0
  60. package/dist/viewport-lock.d.ts.map +1 -0
  61. package/dist/viewport-lock.js +172 -0
  62. package/dist/viewport-lock.js.map +1 -0
  63. package/package.json +49 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 EdV4H
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,52 @@
1
+ # @edv4h/usketch-plugin-dashboard
2
+
3
+ 適用した Canvas 全体を **sortable なフロー・グリッド**にするプラグイン。トップレベルの
4
+ Shape(付箋・画像・カード等、任意の既存 Shape)がグリッドのアイテムになる。各アイテムは
5
+ **自身のサイズに応じて整数セル分を占有**(大きいものは複数セルをまたぐ = ダッシュボードの
6
+ タイル)し、後続は first-fit でその周りに流し込まれる。アイテムはリサイズせず top-left だけ
7
+ スナップする。1つをドラッグして差し込むと、他のアイテムがライブでリフローする。
8
+
9
+ 配置先のセル(グリッド領域)は**オーバーレイ**で可視化され、HUD の「グリッド表示」で
10
+ トグルできる。
11
+
12
+ 専用のウィジェット Shape は追加しない。設定(列数・セルサイズ・間隔・余白・原点)は
13
+ **データのみの `dashboard-config` シングルトン Shape**(描画なし・locked・非 hit-test)に
14
+ 保存され、Yjs 同期と Undo に自然に乗る。並び順は **幾何から導出**(row-major の reading
15
+ order)するので、`order[]` を別途持たず、位置が同期されれば順序も同期・リロード安定になる。
16
+
17
+ ## 使い方
18
+
19
+ ```ts
20
+ import { createDashboardPlugin } from "@edv4h/usketch-plugin-dashboard";
21
+
22
+ createApp({
23
+ plugins: [
24
+ // container / free-position の後に登録する(during-drag reflow を最後の writer に)
25
+ createDashboardPlugin({ columns: 4, cellW: 200, cellH: 140, gap: 16, padding: 24 }),
26
+ ],
27
+ });
28
+ ```
29
+
30
+ `autoCreate: false` を渡すと、config シングルトンの作成(=ボードのダッシュボード化)を
31
+ ホスト側に委ねられる。
32
+
33
+ ## サービス API(`ctx.services` / `app.services`)
34
+
35
+ ```ts
36
+ import { getDashboardApi } from "@edv4h/usketch-plugin-dashboard";
37
+
38
+ const api = getDashboardApi(app.services);
39
+ api?.repack(); // 全アイテムを reading order のセルへ再スナップ(1 command)
40
+ api?.setColumns(6); // 列数変更(Undo 可・再レイアウト)
41
+ api?.setCellSize(240, 160);
42
+ api?.getGridSpec(); // 現在の GridSpec(非ダッシュボードなら null)
43
+ api?.isDashboardBoard();
44
+ ```
45
+
46
+ HUD の「ダッシュボード」設定グループと「整列」アクションからも同じ操作を呼べる。
47
+
48
+ ## 純関数
49
+
50
+ `grid.ts`(`cellTopLeft` / `packGrid` / `packGridWithGap` / `indexFromPoint`)と
51
+ `order.ts`(`readingOrder`)は副作用のない純関数として公開しており、runtime とサービスの
52
+ 両方が同じ経路を通る。
@@ -0,0 +1,48 @@
1
+ import type { BoardStore } from "@edv4h/usketch-shared";
2
+ import { type DashboardConfigData, type DashboardDefaults, type DashboardMode, type ViewportLock } from "./dashboard-config-shape.js";
3
+ import type { GridSpec } from "./grid.js";
4
+ /** Grid settings a caller may change (identity/geometry-only subset of config). */
5
+ export type DashboardConfigPatch = Partial<Pick<DashboardConfigData, "columns" | "cellW" | "cellH" | "gap" | "padding" | "originX" | "originY" | "mode" | "fitToGrid" | "freeOutOfRange" | "viewportLock" | "cellWAuto" | "swap" | "swapThreshold" | "swapDelay">>;
6
+ /** The board's placement mode (defaults to `flow` when not a dashboard/unset). */
7
+ export declare function modeOf(store: BoardStore): DashboardMode;
8
+ /** Whether resizing snaps items to whole-cell sizes (defaults to `false`). */
9
+ export declare function fitToGridOf(store: BoardStore): boolean;
10
+ /** Whether out-of-range shapes are left free (defaults to `true`). */
11
+ export declare function freeOutOfRangeOf(store: BoardStore): boolean;
12
+ /** Whether the scroll-limit is on (defaults to off). Strict `=== true` so a config
13
+ * persisted with the old `"off"|"vertical"|"both"` string coerces to OFF. */
14
+ export declare function viewportLockOf(store: BoardStore): ViewportLock;
15
+ /** Whether the cell width is "auto" (fit to screen) rather than a fixed number. */
16
+ export declare function cellWAutoOf(store: BoardStore): boolean;
17
+ /** Whether drop-onto-occupied swaps the two items (absolute mode). Defaults off. */
18
+ export declare function swapOf(store: BoardStore): boolean;
19
+ /** Minimum overlap ratio (0–1) for a swap to fire (absolute mode). Defaults 0.25. */
20
+ export declare function swapThresholdOf(store: BoardStore): number;
21
+ /** Dwell (ms) before the live avoid fires. Defaults 200 when unset; an explicit 0
22
+ * (immediate) is honored. */
23
+ export declare function swapDelayOf(store: BoardStore): number;
24
+ /**
25
+ * The board's config singleton, or `undefined` if this board isn't a dashboard.
26
+ * If two clients happen to `enable()` at the same time, the board can briefly
27
+ * hold more than one config; pick the one with the smallest `id` so every client
28
+ * converges on the SAME config (rather than depending on Map insertion order,
29
+ * which can differ per client) — the grid then can't diverge across peers.
30
+ */
31
+ export declare function getDashboardConfig(store: BoardStore): DashboardConfigData | undefined;
32
+ /**
33
+ * Return the board's config singleton, creating it first if absent. Creating it
34
+ * is what turns a plain board INTO a dashboard (requirement: the applied Canvas
35
+ * becomes dashboard-only). Call after the store has hydrated so a synced config
36
+ * isn't duplicated.
37
+ */
38
+ export declare function ensureDashboardConfig(store: BoardStore, defaults?: DashboardDefaults): DashboardConfigData;
39
+ /** Every `dashboard-config` shape on the board. Normally 0 or 1, but a concurrent
40
+ * `enable()` across clients can briefly leave more than one — {@link disable}
41
+ * removes them all so the board reliably becomes a non-dashboard again. */
42
+ export declare function getAllDashboardConfigs(store: BoardStore): DashboardConfigData[];
43
+ /** Project the config singleton onto the pure {@link GridSpec} the grid math uses. */
44
+ export declare function gridSpecFromConfig(config: DashboardConfigData): GridSpec;
45
+ /** Direct (non-undoable) config write. The service wraps this in a command when
46
+ * the change should be undoable; programmatic callers can use it as-is. */
47
+ export declare function setConfig(store: BoardStore, patch: DashboardConfigPatch): void;
48
+ //# sourceMappingURL=config-ops.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-ops.d.ts","sourceRoot":"","sources":["../src/config-ops.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAa,MAAM,uBAAuB,CAAC;AACnE,OAAO,EACN,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAGlB,KAAK,YAAY,EACjB,MAAM,6BAA6B,CAAC;AACrC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAE1C,mFAAmF;AACnF,MAAM,MAAM,oBAAoB,GAAG,OAAO,CACzC,IAAI,CACH,mBAAmB,EACjB,SAAS,GACT,OAAO,GACP,OAAO,GACP,KAAK,GACL,SAAS,GACT,SAAS,GACT,SAAS,GACT,MAAM,GACN,WAAW,GACX,gBAAgB,GAChB,cAAc,GACd,WAAW,GACX,MAAM,GACN,eAAe,GACf,WAAW,CACb,CACD,CAAC;AAEF,kFAAkF;AAClF,wBAAgB,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,aAAa,CAEvD;AAED,8EAA8E;AAC9E,wBAAgB,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAEtD;AAED,sEAAsE;AACtE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAE3D;AAED;8EAC8E;AAC9E,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,GAAG,YAAY,CAE9D;AAED,mFAAmF;AACnF,wBAAgB,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAEtD;AAED,oFAAoF;AACpF,wBAAgB,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAEjD;AAED,qFAAqF;AACrF,wBAAgB,eAAe,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAGzD;AAED;8BAC8B;AAC9B,wBAAgB,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAGrD;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,UAAU,GAAG,mBAAmB,GAAG,SAAS,CAQrF;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACpC,KAAK,EAAE,UAAU,EACjB,QAAQ,GAAE,iBAAsB,GAC9B,mBAAmB,CAMrB;AAED;;4EAE4E;AAC5E,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,UAAU,GAAG,mBAAmB,EAAE,CAM/E;AAED,sFAAsF;AACtF,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,mBAAmB,GAAG,QAAQ,CAUxE;AAED;4EAC4E;AAC5E,wBAAgB,SAAS,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,oBAAoB,GAAG,IAAI,CAM9E"}
@@ -0,0 +1,101 @@
1
+ import { isDashboardConfig, makeDashboardConfig, } from "./dashboard-config-shape.js";
2
+ /** The board's placement mode (defaults to `flow` when not a dashboard/unset). */
3
+ export function modeOf(store) {
4
+ return getDashboardConfig(store)?.mode ?? "flow";
5
+ }
6
+ /** Whether resizing snaps items to whole-cell sizes (defaults to `false`). */
7
+ export function fitToGridOf(store) {
8
+ return getDashboardConfig(store)?.fitToGrid ?? false;
9
+ }
10
+ /** Whether out-of-range shapes are left free (defaults to `true`). */
11
+ export function freeOutOfRangeOf(store) {
12
+ return getDashboardConfig(store)?.freeOutOfRange ?? true;
13
+ }
14
+ /** Whether the scroll-limit is on (defaults to off). Strict `=== true` so a config
15
+ * persisted with the old `"off"|"vertical"|"both"` string coerces to OFF. */
16
+ export function viewportLockOf(store) {
17
+ return getDashboardConfig(store)?.viewportLock === true;
18
+ }
19
+ /** Whether the cell width is "auto" (fit to screen) rather than a fixed number. */
20
+ export function cellWAutoOf(store) {
21
+ return getDashboardConfig(store)?.cellWAuto === true;
22
+ }
23
+ /** Whether drop-onto-occupied swaps the two items (absolute mode). Defaults off. */
24
+ export function swapOf(store) {
25
+ return getDashboardConfig(store)?.swap === true;
26
+ }
27
+ /** Minimum overlap ratio (0–1) for a swap to fire (absolute mode). Defaults 0.25. */
28
+ export function swapThresholdOf(store) {
29
+ const t = getDashboardConfig(store)?.swapThreshold;
30
+ return typeof t === "number" && Number.isFinite(t) ? Math.min(Math.max(t, 0), 1) : 0.25;
31
+ }
32
+ /** Dwell (ms) before the live avoid fires. Defaults 200 when unset; an explicit 0
33
+ * (immediate) is honored. */
34
+ export function swapDelayOf(store) {
35
+ const d = getDashboardConfig(store)?.swapDelay;
36
+ return typeof d === "number" && Number.isFinite(d) && d >= 0 ? d : 200;
37
+ }
38
+ /**
39
+ * The board's config singleton, or `undefined` if this board isn't a dashboard.
40
+ * If two clients happen to `enable()` at the same time, the board can briefly
41
+ * hold more than one config; pick the one with the smallest `id` so every client
42
+ * converges on the SAME config (rather than depending on Map insertion order,
43
+ * which can differ per client) — the grid then can't diverge across peers.
44
+ */
45
+ export function getDashboardConfig(store) {
46
+ let chosen;
47
+ for (const [, shape] of store.getShapes()) {
48
+ if (isDashboardConfig(shape) && (chosen === undefined || shape.id < chosen.id)) {
49
+ chosen = shape;
50
+ }
51
+ }
52
+ return chosen;
53
+ }
54
+ /**
55
+ * Return the board's config singleton, creating it first if absent. Creating it
56
+ * is what turns a plain board INTO a dashboard (requirement: the applied Canvas
57
+ * becomes dashboard-only). Call after the store has hydrated so a synced config
58
+ * isn't duplicated.
59
+ */
60
+ export function ensureDashboardConfig(store, defaults = {}) {
61
+ const existing = getDashboardConfig(store);
62
+ if (existing)
63
+ return existing;
64
+ const config = makeDashboardConfig(defaults);
65
+ store.addShape(config);
66
+ return config;
67
+ }
68
+ /** Every `dashboard-config` shape on the board. Normally 0 or 1, but a concurrent
69
+ * `enable()` across clients can briefly leave more than one — {@link disable}
70
+ * removes them all so the board reliably becomes a non-dashboard again. */
71
+ export function getAllDashboardConfigs(store) {
72
+ const configs = [];
73
+ for (const [, shape] of store.getShapes()) {
74
+ if (isDashboardConfig(shape))
75
+ configs.push(shape);
76
+ }
77
+ return configs;
78
+ }
79
+ /** Project the config singleton onto the pure {@link GridSpec} the grid math uses. */
80
+ export function gridSpecFromConfig(config) {
81
+ return {
82
+ columns: config.columns,
83
+ cellW: config.cellW,
84
+ cellH: config.cellH,
85
+ gap: config.gap,
86
+ padding: config.padding,
87
+ originX: config.originX,
88
+ originY: config.originY,
89
+ };
90
+ }
91
+ /** Direct (non-undoable) config write. The service wraps this in a command when
92
+ * the change should be undoable; programmatic callers can use it as-is. */
93
+ export function setConfig(store, patch) {
94
+ const config = getDashboardConfig(store);
95
+ if (!config)
96
+ return;
97
+ // Config carries custom fields on top of ShapeData; the store merges them
98
+ // verbatim (same pattern as the map plugin's shape-field writes).
99
+ store.updateShape(config.id, patch);
100
+ }
101
+ //# sourceMappingURL=config-ops.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-ops.js","sourceRoot":"","sources":["../src/config-ops.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { ShapeDefinition } from "@edv4h/usketch-shared";
2
+ import { type DashboardDefaults } from "./dashboard-config-shape.js";
3
+ export declare function createDashboardConfigShapeDefinition(defaults?: DashboardDefaults): ShapeDefinition;
4
+ //# sourceMappingURL=dashboard-config-shape-def.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard-config-shape-def.d.ts","sourceRoot":"","sources":["../src/dashboard-config-shape-def.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAA0B,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACrF,OAAO,EAEN,KAAK,iBAAiB,EAEtB,MAAM,6BAA6B,CAAC;AAErC,wBAAgB,oCAAoC,CACnD,QAAQ,GAAE,iBAAsB,GAC9B,eAAe,CA6BjB"}
@@ -0,0 +1,33 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { makeDashboardConfig, } from "./dashboard-config-shape.js";
3
+ export function createDashboardConfigShapeDefinition(defaults = {}) {
4
+ return {
5
+ render: () => _jsx("g", {}),
6
+ renderTarget: "svg",
7
+ getBounds: () => ({ x: 0, y: 0, width: 0, height: 0 }),
8
+ hitTest: () => false,
9
+ resizable: false,
10
+ resize: (data) => data,
11
+ createDefault: (params) => ({ ...makeDashboardConfig(defaults), id: params.id }),
12
+ serializeForAi: (data) => {
13
+ const d = data;
14
+ return {
15
+ kind: "dashboard-config",
16
+ columns: d.columns,
17
+ cell: [d.cellW, d.cellH],
18
+ gap: d.gap,
19
+ };
20
+ },
21
+ debugFields: (data) => {
22
+ const d = data;
23
+ return {
24
+ columns: d.columns,
25
+ cell: `${d.cellW}×${d.cellH}`,
26
+ gap: d.gap,
27
+ padding: d.padding,
28
+ origin: `${d.originX},${d.originY}`,
29
+ };
30
+ },
31
+ };
32
+ }
33
+ //# sourceMappingURL=dashboard-config-shape-def.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard-config-shape-def.js","sourceRoot":"","sources":["../src/dashboard-config-shape-def.tsx"],"names":[],"mappings":";AAIA,OAAO,EAGN,mBAAmB,GACnB,MAAM,6BAA6B,CAAC;AAErC,MAAM,UAAU,oCAAoC,CACnD,QAAQ,GAAsB,EAAE;IAEhC,OAAO;QACN,MAAM,EAAE,GAAG,EAAE,CAAC,aAAK;QACnB,YAAY,EAAE,KAAK;QACnB,SAAS,EAAE,GAAgB,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;QACnE,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK;QACpB,SAAS,EAAE,KAAK;QAChB,MAAM,EAAE,CAAC,IAAI,EAAa,EAAE,CAAC,IAAI;QACjC,aAAa,EAAE,CAAC,MAAM,EAAa,EAAE,CAAC,CAAC,EAAE,GAAG,mBAAmB,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC;QAC3F,cAAc,EAAE,CAAC,IAAI,EAA2B,EAAE;YACjD,MAAM,CAAC,GAAG,IAA2B,CAAC;YACtC,OAAO;gBACN,IAAI,EAAE,kBAAkB;gBACxB,OAAO,EAAE,CAAC,CAAC,OAAO;gBAClB,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC;gBACxB,GAAG,EAAE,CAAC,CAAC,GAAG;aACV,CAAC;QACH,CAAC;QACD,WAAW,EAAE,CAAC,IAAI,EAA2B,EAAE;YAC9C,MAAM,CAAC,GAAG,IAA2B,CAAC;YACtC,OAAO;gBACN,OAAO,EAAE,CAAC,CAAC,OAAO;gBAClB,IAAI,EAAE,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,EAAE;gBAC7B,GAAG,EAAE,CAAC,CAAC,GAAG;gBACV,OAAO,EAAE,CAAC,CAAC,OAAO;gBAClB,MAAM,EAAE,GAAG,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO,EAAE;aACnC,CAAC;QACH,CAAC;KACD,CAAC;AACH,CAAC"}
@@ -0,0 +1,71 @@
1
+ import type { ShapeData } from "@edv4h/usketch-shared";
2
+ export declare const DASHBOARD_CONFIG_TYPE = "dashboard-config";
3
+ /**
4
+ * Placement mode:
5
+ * - `flow` — items pack compactly in reading order (sortable; no gaps).
6
+ * - `absolute` — each item stays in the cell it's dropped on (gaps allowed).
7
+ */
8
+ export type DashboardMode = "flow" | "absolute";
9
+ /**
10
+ * Scroll-limit toggle. When ON, the viewport is locked to 100% zoom and the cell
11
+ * width auto-fits so the grid exactly fills the screen width — so there's no
12
+ * horizontal room and you scroll vertically only, bounded to the content. When OFF,
13
+ * pan/zoom are free. (Was a `"off"|"vertical"|"both"` mode; now a simple on/off.)
14
+ */
15
+ export type ViewportLock = boolean;
16
+ /** Grid settings persisted on the singleton. Geometry (`originX`/`originY`) lives
17
+ * here too so the grid anchor is stable across reflows and reloads. */
18
+ export interface DashboardConfigData extends ShapeData {
19
+ type: "dashboard-config";
20
+ columns: number;
21
+ cellW: number;
22
+ cellH: number;
23
+ gap: number;
24
+ padding: number;
25
+ originX: number;
26
+ originY: number;
27
+ mode: DashboardMode;
28
+ /** When true, resizing an item snaps its size to the nearest whole-cell span. */
29
+ fitToGrid: boolean;
30
+ /** When true, a shape dragged OUT of the grid's column range is left free
31
+ * (unmanaged). When false, every top-level shape is managed regardless of
32
+ * position. */
33
+ freeOutOfRange: boolean;
34
+ /** Scroll-limit toggle. See {@link ViewportLock}. */
35
+ viewportLock: ViewportLock;
36
+ /** Whether the cell WIDTH is "auto" (fit to the screen width). Drives the
37
+ * scroll-limit mode: fixed numeric width → vertical-only; auto → both axes. */
38
+ cellWAuto: boolean;
39
+ /** In `absolute` mode, whether dropping an item onto an occupied cell makes that
40
+ * occupant AVOID it — stepping to the nearest empty cell — instead of the drop
41
+ * colliding. (Named `swap` historically.) No effect in `flow` (always reorders). */
42
+ swap: boolean;
43
+ /** Avoid trigger sensitivity (0–1): the minimum overlap ratio between the dropped
44
+ * item and an occupant for the occupant to move aside. Lower = easier. */
45
+ swapThreshold: number;
46
+ /** Dwell before the LIVE avoid fires (ms): how long the dragged item must hover an
47
+ * occupant before it steps aside. 0 = immediate. Only gates the drag-time preview;
48
+ * a drop always resolves immediately. */
49
+ swapDelay: number;
50
+ }
51
+ export interface DashboardDefaults {
52
+ columns?: number;
53
+ cellW?: number;
54
+ cellH?: number;
55
+ gap?: number;
56
+ padding?: number;
57
+ originX?: number;
58
+ originY?: number;
59
+ mode?: DashboardMode;
60
+ fitToGrid?: boolean;
61
+ freeOutOfRange?: boolean;
62
+ viewportLock?: ViewportLock;
63
+ cellWAuto?: boolean;
64
+ swap?: boolean;
65
+ swapThreshold?: number;
66
+ swapDelay?: number;
67
+ }
68
+ export declare const DASHBOARD_DEFAULTS: Required<DashboardDefaults>;
69
+ export declare function isDashboardConfig(shape: ShapeData): shape is DashboardConfigData;
70
+ export declare function makeDashboardConfig(defaults?: DashboardDefaults): DashboardConfigData;
71
+ //# sourceMappingURL=dashboard-config-shape.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard-config-shape.d.ts","sourceRoot":"","sources":["../src/dashboard-config-shape.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAGvD,eAAO,MAAM,qBAAqB,qBAAqB,CAAC;AAExD;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,UAAU,CAAC;AAEhD;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GAAG,OAAO,CAAC;AAEnC;wEACwE;AACxE,MAAM,WAAW,mBAAoB,SAAQ,SAAS;IACrD,IAAI,EAAE,kBAAkB,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,aAAa,CAAC;IACpB,iFAAiF;IACjF,SAAS,EAAE,OAAO,CAAC;IACnB;;oBAEgB;IAChB,cAAc,EAAE,OAAO,CAAC;IACxB,qDAAqD;IACrD,YAAY,EAAE,YAAY,CAAC;IAC3B;oFACgF;IAChF,SAAS,EAAE,OAAO,CAAC;IACnB;;yFAEqF;IACrF,IAAI,EAAE,OAAO,CAAC;IACd;+EAC2E;IAC3E,aAAa,EAAE,MAAM,CAAC;IACtB;;8CAE0C;IAC1C,SAAS,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,eAAO,MAAM,kBAAkB,EAAE,QAAQ,CAAC,iBAAiB,CAgB1D,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,SAAS,GAAG,KAAK,IAAI,mBAAmB,CAEhF;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,GAAE,iBAAsB,GAAG,mBAAmB,CA2BzF"}
@@ -0,0 +1,51 @@
1
+ import { generateId } from "@edv4h/usketch-shared";
2
+ export const DASHBOARD_CONFIG_TYPE = "dashboard-config";
3
+ export const DASHBOARD_DEFAULTS = {
4
+ columns: 4,
5
+ cellW: 200,
6
+ cellH: 140,
7
+ gap: 16,
8
+ padding: 24,
9
+ originX: 0,
10
+ originY: 0,
11
+ mode: "absolute",
12
+ fitToGrid: true,
13
+ freeOutOfRange: false,
14
+ viewportLock: true,
15
+ cellWAuto: true,
16
+ swap: true,
17
+ swapThreshold: 0.25,
18
+ swapDelay: 200,
19
+ };
20
+ export function isDashboardConfig(shape) {
21
+ return shape.type === DASHBOARD_CONFIG_TYPE;
22
+ }
23
+ export function makeDashboardConfig(defaults = {}) {
24
+ const d = { ...DASHBOARD_DEFAULTS, ...defaults };
25
+ return {
26
+ id: generateId(),
27
+ type: DASHBOARD_CONFIG_TYPE,
28
+ x: 0,
29
+ y: 0,
30
+ width: 0,
31
+ height: 0,
32
+ style: { fill: "transparent", stroke: "transparent", strokeWidth: 0, opacity: 1 },
33
+ columns: d.columns,
34
+ cellW: d.cellW,
35
+ cellH: d.cellH,
36
+ gap: d.gap,
37
+ padding: d.padding,
38
+ originX: d.originX,
39
+ originY: d.originY,
40
+ mode: d.mode,
41
+ fitToGrid: d.fitToGrid,
42
+ freeOutOfRange: d.freeOutOfRange,
43
+ viewportLock: d.viewportLock,
44
+ cellWAuto: d.cellWAuto,
45
+ swap: d.swap,
46
+ swapThreshold: d.swapThreshold,
47
+ swapDelay: d.swapDelay,
48
+ locked: true,
49
+ };
50
+ }
51
+ //# sourceMappingURL=dashboard-config-shape.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard-config-shape.js","sourceRoot":"","sources":["../src/dashboard-config-shape.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAEnD,MAAM,CAAC,MAAM,qBAAqB,GAAG,kBAAkB,CAAC;AAuExD,MAAM,CAAC,MAAM,kBAAkB,GAAgC;IAC9D,OAAO,EAAE,CAAC;IACV,KAAK,EAAE,GAAG;IACV,KAAK,EAAE,GAAG;IACV,GAAG,EAAE,EAAE;IACP,OAAO,EAAE,EAAE;IACX,OAAO,EAAE,CAAC;IACV,OAAO,EAAE,CAAC;IACV,IAAI,EAAE,UAAU;IAChB,SAAS,EAAE,IAAI;IACf,cAAc,EAAE,KAAK;IACrB,YAAY,EAAE,IAAI;IAClB,SAAS,EAAE,IAAI;IACf,IAAI,EAAE,IAAI;IACV,aAAa,EAAE,IAAI;IACnB,SAAS,EAAE,GAAG;CACd,CAAC;AAEF,MAAM,UAAU,iBAAiB,CAAC,KAAgB;IACjD,OAAO,KAAK,CAAC,IAAI,KAAK,qBAAqB,CAAC;AAC7C,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,QAAQ,GAAsB,EAAE;IACnE,MAAM,CAAC,GAAG,EAAE,GAAG,kBAAkB,EAAE,GAAG,QAAQ,EAAE,CAAC;IACjD,OAAO;QACN,EAAE,EAAE,UAAU,EAAE;QAChB,IAAI,EAAE,qBAAqB;QAC3B,CAAC,EAAE,CAAC;QACJ,CAAC,EAAE,CAAC;QACJ,KAAK,EAAE,CAAC;QACR,MAAM,EAAE,CAAC;QACT,KAAK,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,aAAa,EAAE,WAAW,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE;QACjF,OAAO,EAAE,CAAC,CAAC,OAAO;QAClB,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,GAAG,EAAE,CAAC,CAAC,GAAG;QACV,OAAO,EAAE,CAAC,CAAC,OAAO;QAClB,OAAO,EAAE,CAAC,CAAC,OAAO;QAClB,OAAO,EAAE,CAAC,CAAC,OAAO;QAClB,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,SAAS,EAAE,CAAC,CAAC,SAAS;QACtB,cAAc,EAAE,CAAC,CAAC,cAAc;QAChC,YAAY,EAAE,CAAC,CAAC,YAAY;QAC5B,SAAS,EAAE,CAAC,CAAC,SAAS;QACtB,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,aAAa,EAAE,CAAC,CAAC,aAAa;QAC9B,SAAS,EAAE,CAAC,CAAC,SAAS;QACtB,MAAM,EAAE,IAAI;KACZ,CAAC;AACH,CAAC"}
@@ -0,0 +1,23 @@
1
+ import type { PluginContext } from "@edv4h/usketch-shared";
2
+ /** Run `fn` with the dashboard-write guard raised so the reflow runtime ignores
3
+ * the store mutations it produces. Exported so the service can guard its own
4
+ * config command's execute/undo the same way. */
5
+ export declare function runGuarded(fn: () => void): void;
6
+ /**
7
+ * Snap every item to its reading-order cell, span-aware, in ONE guarded+undoable
8
+ * command. Used for non-drag changes (add/remove) and the "整列" action / service
9
+ * `repack()`. No-op writes are dropped, so it's safe to call speculatively.
10
+ */
11
+ export declare function repackBoard(ctx: PluginContext, includeAll?: boolean): void;
12
+ /**
13
+ * Repack every item to its reading-order cell WITHOUT a command (guarded, no undo
14
+ * entry). For automatic layout the user didn't ask for — e.g. the scroll-lock's
15
+ * auto cell-width refit on resize — where polluting the undo stack would be wrong.
16
+ */
17
+ export declare function repackBoardTransient(ctx: PluginContext): void;
18
+ /**
19
+ * Wire the live-reflow runtime. Returns a teardown that removes every listener
20
+ * and cancels any pending frame.
21
+ */
22
+ export declare function setupDashboard(ctx: PluginContext): () => void;
23
+ //# sourceMappingURL=dashboard-runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard-runtime.d.ts","sourceRoot":"","sources":["../src/dashboard-runtime.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAuB,aAAa,EAAa,MAAM,uBAAuB,CAAC;AAiC3F;;kDAEkD;AAClD,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,IAAI,CAO/C;AAyJD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,aAAa,EAAE,UAAU,UAAQ,GAAG,IAAI,CAwBxE;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAiB7D;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,IAAI,CAmhB7D"}