@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
@@ -0,0 +1,12 @@
1
+ import type { UsketchPlugin } from "@edv4h/usketch-shared";
2
+ import { type DashboardDefaults } from "./dashboard-config-shape.js";
3
+ export interface DashboardPluginOptions extends DashboardDefaults {
4
+ /**
5
+ * Create the config singleton on setup so the board becomes a dashboard
6
+ * immediately (default `true`). Set `false` to leave activation to a host
7
+ * calling the service / creating the config itself.
8
+ */
9
+ autoCreate?: boolean;
10
+ }
11
+ export declare function createDashboardPlugin(options?: DashboardPluginOptions): UsketchPlugin;
12
+ //# sourceMappingURL=plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAiB,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE1E,OAAO,EAAyB,KAAK,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAQ5F,MAAM,WAAW,sBAAuB,SAAQ,iBAAiB;IAChE;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,wBAAgB,qBAAqB,CAAC,OAAO,GAAE,sBAA2B,GAAG,aAAa,CAsDzF"}
package/dist/plugin.js ADDED
@@ -0,0 +1,59 @@
1
+ import { ensureDashboardConfig } from "./config-ops.js";
2
+ import { DASHBOARD_CONFIG_TYPE } from "./dashboard-config-shape.js";
3
+ import { createDashboardConfigShapeDefinition } from "./dashboard-config-shape-def.js";
4
+ import { repackBoard, setupDashboard } from "./dashboard-runtime.js";
5
+ import { createDashboardApi, dashboardService } from "./dashboard-service.js";
6
+ import { gridOverlayLayer, resetGridOverlayVisible } from "./grid-overlay.js";
7
+ import { registerDashboardHud } from "./register-dashboard-hud.js";
8
+ import { setupViewportLock } from "./viewport-lock.js";
9
+ export function createDashboardPlugin(options = {}) {
10
+ const { autoCreate = true, ...defaults } = options;
11
+ return {
12
+ id: "usketch-plugin-dashboard",
13
+ name: "ダッシュボード",
14
+ setup(ctx) {
15
+ ctx.shapes.register(DASHBOARD_CONFIG_TYPE, createDashboardConfigShapeDefinition(defaults));
16
+ // Grid overlay: shows the target cells so it's clear where items land. It
17
+ // renders nothing on a non-dashboard board, so it's safe to always register.
18
+ resetGridOverlayVisible();
19
+ ctx.layers.register(gridOverlayLayer);
20
+ const api = createDashboardApi(ctx, defaults);
21
+ // Disposed guard: the autoCreate task WRITES to the store, and a microtask
22
+ // can't be cancelled — without this it could run after teardown (an
23
+ // immediate `app.destroy()`, or setup-rollback) and mutate a destroyed
24
+ // app's store. Checked inside the deferred task.
25
+ let disposed = false;
26
+ // Defer to a microtask so shapes hydrated synchronously on load (incl. a
27
+ // synced config from another client) are visible first — `ensure` is a
28
+ // no-op when a config already exists, avoiding a duplicate singleton.
29
+ // Then pack the existing top-level shapes so the board is actually laid
30
+ // out on the grid (creating the config alone doesn't move anything, and
31
+ // the config's own `shape:added` isn't an item so it won't trigger a
32
+ // repack).
33
+ if (autoCreate) {
34
+ queueMicrotask(() => {
35
+ if (disposed)
36
+ return;
37
+ ensureDashboardConfig(ctx.store, defaults);
38
+ repackBoard(ctx);
39
+ });
40
+ }
41
+ const stopRuntime = setupDashboard(ctx);
42
+ const stopViewportLock = setupViewportLock(ctx);
43
+ const stopHud = registerDashboardHud(ctx, api);
44
+ // Provide the service LAST: `createApp` can only roll back a failed setup
45
+ // via the teardown we return, so if an earlier step throws the service was
46
+ // never registered and can't leak. (Same ordering as usketch-plugin-map.)
47
+ const unprovideService = dashboardService.provide(ctx.services, api);
48
+ return () => {
49
+ disposed = true;
50
+ unprovideService();
51
+ stopHud();
52
+ stopRuntime();
53
+ stopViewportLock();
54
+ ctx.layers.unregister(gridOverlayLayer.id);
55
+ };
56
+ },
57
+ };
58
+ }
59
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,qBAAqB,EAA0B,MAAM,6BAA6B,CAAC;AAC5F,OAAO,EAAE,oCAAoC,EAAE,MAAM,iCAAiC,CAAC;AACvF,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACrE,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC9E,OAAO,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAC9E,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAWvD,MAAM,UAAU,qBAAqB,CAAC,OAAO,GAA2B,EAAE;IACzE,MAAM,EAAE,UAAU,GAAG,IAAI,EAAE,GAAG,QAAQ,EAAE,GAAG,OAAO,CAAC;IACnD,OAAO;QACN,EAAE,EAAE,0BAA0B;QAC9B,IAAI,EAAE,SAAS;QACf,KAAK,CAAC,GAAkB;YACvB,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,qBAAqB,EAAE,oCAAoC,CAAC,QAAQ,CAAC,CAAC,CAAC;YAE3F,0EAA0E;YAC1E,6EAA6E;YAC7E,uBAAuB,EAAE,CAAC;YAC1B,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC;YAEtC,MAAM,GAAG,GAAG,kBAAkB,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;YAE9C,2EAA2E;YAC3E,oEAAoE;YACpE,uEAAuE;YACvE,iDAAiD;YACjD,IAAI,QAAQ,GAAG,KAAK,CAAC;YAErB,yEAAyE;YACzE,uEAAuE;YACvE,sEAAsE;YACtE,wEAAwE;YACxE,wEAAwE;YACxE,qEAAqE;YACrE,WAAW;YACX,IAAI,UAAU,EAAE,CAAC;gBAChB,cAAc,CAAC,GAAG,EAAE;oBACnB,IAAI,QAAQ;wBAAE,OAAO;oBACrB,qBAAqB,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;oBAC3C,WAAW,CAAC,GAAG,CAAC,CAAC;gBAClB,CAAC,CAAC,CAAC;YACJ,CAAC;YAED,MAAM,WAAW,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;YACxC,MAAM,gBAAgB,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC;YAChD,MAAM,OAAO,GAAG,oBAAoB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;YAC/C,0EAA0E;YAC1E,2EAA2E;YAC3E,0EAA0E;YAC1E,MAAM,gBAAgB,GAAG,gBAAgB,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;YAErE,OAAO,GAAG,EAAE;gBACX,QAAQ,GAAG,IAAI,CAAC;gBAChB,gBAAgB,EAAE,CAAC;gBACnB,OAAO,EAAE,CAAC;gBACV,WAAW,EAAE,CAAC;gBACd,gBAAgB,EAAE,CAAC;gBACnB,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC;YAC5C,CAAC,CAAC;QACH,CAAC;KACD,CAAC;AACH,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { PluginContext } from "@edv4h/usketch-shared";
2
+ import type { DashboardApi } from "./dashboard-service.js";
3
+ /** Register the dashboard's HUD settings + arrange action. Returns a teardown. */
4
+ export declare function registerDashboardHud(ctx: PluginContext, api: DashboardApi): () => void;
5
+ //# sourceMappingURL=register-dashboard-hud.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register-dashboard-hud.d.ts","sourceRoot":"","sources":["../src/register-dashboard-hud.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAG3D,kFAAkF;AAClF,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,aAAa,EAAE,GAAG,EAAE,YAAY,GAAG,MAAM,IAAI,CAkKtF"}
@@ -0,0 +1,173 @@
1
+ import { isGridOverlayVisible, setGridOverlayVisible } from "./grid-overlay.js";
2
+ /** Register the dashboard's HUD settings + arrange action. Returns a teardown. */
3
+ export function registerDashboardHud(ctx, api) {
4
+ const unregisterSettings = ctx.hud.registerSettings({
5
+ id: "usketch-plugin-dashboard:settings",
6
+ label: "ダッシュボード",
7
+ order: 10,
8
+ fields: [
9
+ {
10
+ name: "mode",
11
+ label: "配置",
12
+ type: "enum",
13
+ options: [
14
+ { value: "flow", label: "詰める(sortable)" },
15
+ { value: "absolute", label: "そのまま(自由)" },
16
+ ],
17
+ },
18
+ { name: "columns", label: "列数", type: "number", min: 1, max: 12, step: 1 },
19
+ { name: "cellWidth", label: "セル幅", type: "number", min: 40, max: 800, step: 10 },
20
+ { name: "cellWAuto", label: "幅をAuto(画面幅・縦のみ)", type: "boolean" },
21
+ { name: "cellHeight", label: "セル高", type: "number", min: 40, max: 800, step: 10 },
22
+ { name: "gap", label: "間隔", type: "number", min: 0, max: 100, step: 2 },
23
+ { name: "padding", label: "余白", type: "number", min: 0, max: 200, step: 4 },
24
+ { name: "fitToGrid", label: "セルに合わせる", type: "boolean" },
25
+ { name: "swap", label: "避ける", type: "boolean" },
26
+ { name: "swapThreshold", label: "避け閾値%", type: "number", min: 0, max: 100, step: 5 },
27
+ { name: "swapDelay", label: "避けディレイ(ms)", type: "number", min: 0, max: 1000, step: 50 },
28
+ { name: "freeOutOfRange", label: "範囲外は自由", type: "boolean" },
29
+ { name: "viewportLock", label: "スクロール制限", type: "boolean" },
30
+ ],
31
+ get(name) {
32
+ if (name === "mode")
33
+ return api.getMode();
34
+ if (name === "fitToGrid")
35
+ return api.getFitToGrid();
36
+ if (name === "swap")
37
+ return api.getSwap();
38
+ if (name === "swapThreshold")
39
+ return Math.round(api.getSwapThreshold() * 100);
40
+ if (name === "swapDelay")
41
+ return api.getSwapDelay();
42
+ if (name === "freeOutOfRange")
43
+ return api.getFreeOutOfRange();
44
+ if (name === "viewportLock")
45
+ return api.getViewportLock();
46
+ if (name === "cellWAuto")
47
+ return api.getCellWidthAuto();
48
+ const spec = api.getGridSpec();
49
+ if (!spec)
50
+ return undefined;
51
+ switch (name) {
52
+ case "columns":
53
+ return spec.columns;
54
+ case "cellWidth":
55
+ return spec.cellW;
56
+ case "cellHeight":
57
+ return spec.cellH;
58
+ case "gap":
59
+ return spec.gap;
60
+ case "padding":
61
+ return spec.padding;
62
+ default:
63
+ return undefined;
64
+ }
65
+ },
66
+ set(name, value) {
67
+ if (name === "mode") {
68
+ if (value === "flow" || value === "absolute")
69
+ api.setMode(value);
70
+ return;
71
+ }
72
+ if (name === "fitToGrid") {
73
+ api.setFitToGrid(value === true || value === "true");
74
+ return;
75
+ }
76
+ if (name === "swap") {
77
+ api.setSwap(value === true || value === "true");
78
+ return;
79
+ }
80
+ if (name === "freeOutOfRange") {
81
+ api.setFreeOutOfRange(value === true || value === "true");
82
+ return;
83
+ }
84
+ if (name === "viewportLock") {
85
+ api.setViewportLock(value === true || value === "true");
86
+ return;
87
+ }
88
+ if (name === "cellWAuto") {
89
+ api.setCellWidthAuto(value === true || value === "true");
90
+ return;
91
+ }
92
+ const n = Number(value);
93
+ if (!Number.isFinite(n))
94
+ return;
95
+ const spec = api.getGridSpec();
96
+ switch (name) {
97
+ case "columns":
98
+ api.setColumns(n);
99
+ break;
100
+ case "cellWidth":
101
+ // A manual width edit turns Auto off (it's now a fixed number).
102
+ if (spec) {
103
+ api.setCellWidthAuto(false);
104
+ api.setCellSize(n, spec.cellH);
105
+ }
106
+ break;
107
+ case "cellHeight":
108
+ if (spec)
109
+ api.setCellSize(spec.cellW, n);
110
+ break;
111
+ case "gap":
112
+ api.setGap(n);
113
+ break;
114
+ case "padding":
115
+ api.setPadding(n);
116
+ break;
117
+ case "swapThreshold":
118
+ api.setSwapThreshold(n / 100); // percent field → 0–1 ratio
119
+ break;
120
+ case "swapDelay":
121
+ api.setSwapDelay(n);
122
+ break;
123
+ }
124
+ },
125
+ subscribe: (listener) => api.onChange(listener),
126
+ });
127
+ const unregisterEnable = ctx.actions.register({
128
+ id: "usketch-plugin-dashboard:enable",
129
+ label: "ダッシュボード化",
130
+ group: "ダッシュボード",
131
+ order: 0,
132
+ run: () => api.enable(),
133
+ // Only offered when the board isn't yet a dashboard (re-packing an active
134
+ // one is what「整列」is for).
135
+ isEnabled: () => !api.isDashboardBoard(),
136
+ isActive: () => api.isDashboardBoard(),
137
+ });
138
+ const unregisterDisable = ctx.actions.register({
139
+ id: "usketch-plugin-dashboard:disable",
140
+ label: "ダッシュボード解除",
141
+ group: "ダッシュボード",
142
+ order: 1,
143
+ run: () => api.disable(),
144
+ // A no-op unless the board is a dashboard — disable it so the HUD doesn't
145
+ // present a dead control.
146
+ isEnabled: () => api.isDashboardBoard(),
147
+ });
148
+ const unregisterArrange = ctx.actions.register({
149
+ id: "usketch-plugin-dashboard:arrange",
150
+ label: "整列",
151
+ group: "ダッシュボード",
152
+ order: 2,
153
+ run: () => api.repack(),
154
+ isEnabled: () => api.isDashboardBoard(),
155
+ });
156
+ const unregisterToggleGrid = ctx.actions.register({
157
+ id: "usketch-plugin-dashboard:toggle-grid",
158
+ label: "グリッド表示",
159
+ group: "ダッシュボード",
160
+ order: 3,
161
+ run: () => setGridOverlayVisible(!isGridOverlayVisible()),
162
+ isActive: () => isGridOverlayVisible(),
163
+ isEnabled: () => api.isDashboardBoard(),
164
+ });
165
+ return () => {
166
+ unregisterSettings();
167
+ unregisterEnable();
168
+ unregisterDisable();
169
+ unregisterArrange();
170
+ unregisterToggleGrid();
171
+ };
172
+ }
173
+ //# sourceMappingURL=register-dashboard-hud.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register-dashboard-hud.js","sourceRoot":"","sources":["../src/register-dashboard-hud.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /** Turn the slide transition on/off (follows whether the board is a dashboard). */
2
+ export declare function setSlideActive(on: boolean): void;
3
+ /** Exclude the actively-dragged shape from the transition (null re-includes all). */
4
+ export declare function setSlideExclude(id: string | null): void;
5
+ /** Re-include `id` ONLY if it's still the excluded one (so a new drag that already
6
+ * excluded a different shape isn't clobbered by a stale deferred clear). */
7
+ export declare function clearSlideExclude(id: string): void;
8
+ /** Remove the stylesheet and reset state (plugin teardown). */
9
+ export declare function teardownSlide(): void;
10
+ //# sourceMappingURL=slide-animation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slide-animation.d.ts","sourceRoot":"","sources":["../src/slide-animation.ts"],"names":[],"mappings":"AA0CA,mFAAmF;AACnF,wBAAgB,cAAc,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAIhD;AAED,qFAAqF;AACrF,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAIvD;AAED;6EAC6E;AAC7E,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAElD;AAED,+DAA+D;AAC/D,wBAAgB,aAAa,IAAI,IAAI,CAIpC"}
@@ -0,0 +1,67 @@
1
+ // A CSS-only slide animation for dashboard reflow: shapes are positioned by the DOM
2
+ // renderer with `left`/`top` (each tagged `data-shape-id`), so a transition on those
3
+ // properties makes every programmatic move (reflow, avoid, repack, drop-snap) glide
4
+ // instead of jump. The one shape being actively dragged is EXCLUDED so it tracks the
5
+ // pointer with no lag. The rule lives in one <style> element toggled on/off with the
6
+ // dashboard, so non-dashboard boards are unaffected.
7
+ const STYLE_ID = "usketch-dashboard-slide";
8
+ const DURATION_MS = 180;
9
+ const EASING = "cubic-bezier(.2,.8,.2,1)";
10
+ let active = false;
11
+ let excludeId = null;
12
+ /** Escape a shape id for use inside a CSS attribute selector. */
13
+ function cssEscape(v) {
14
+ const anyCss = globalThis.CSS;
15
+ if (anyCss?.escape)
16
+ return anyCss.escape(v);
17
+ return v.replace(/["\\]/g, "\\$&");
18
+ }
19
+ function styleEl() {
20
+ if (typeof document === "undefined")
21
+ return null;
22
+ let el = document.getElementById(STYLE_ID);
23
+ if (!el) {
24
+ el = document.createElement("style");
25
+ el.id = STYLE_ID;
26
+ document.head.appendChild(el);
27
+ }
28
+ return el;
29
+ }
30
+ function render() {
31
+ const el = styleEl();
32
+ if (!el)
33
+ return;
34
+ if (!active) {
35
+ el.textContent = "";
36
+ return;
37
+ }
38
+ const not = excludeId ? `:not([data-shape-id="${cssEscape(excludeId)}"])` : "";
39
+ el.textContent = `[data-shape-id]${not}{transition:left ${DURATION_MS}ms ${EASING},top ${DURATION_MS}ms ${EASING}}`;
40
+ }
41
+ /** Turn the slide transition on/off (follows whether the board is a dashboard). */
42
+ export function setSlideActive(on) {
43
+ if (active === on)
44
+ return;
45
+ active = on;
46
+ render();
47
+ }
48
+ /** Exclude the actively-dragged shape from the transition (null re-includes all). */
49
+ export function setSlideExclude(id) {
50
+ if (excludeId === id)
51
+ return;
52
+ excludeId = id;
53
+ render();
54
+ }
55
+ /** Re-include `id` ONLY if it's still the excluded one (so a new drag that already
56
+ * excluded a different shape isn't clobbered by a stale deferred clear). */
57
+ export function clearSlideExclude(id) {
58
+ if (excludeId === id)
59
+ setSlideExclude(null);
60
+ }
61
+ /** Remove the stylesheet and reset state (plugin teardown). */
62
+ export function teardownSlide() {
63
+ active = false;
64
+ excludeId = null;
65
+ styleEl()?.remove();
66
+ }
67
+ //# sourceMappingURL=slide-animation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slide-animation.js","sourceRoot":"","sources":["../src/slide-animation.ts"],"names":[],"mappings":"AAAA,oFAAoF;AACpF,qFAAqF;AACrF,oFAAoF;AACpF,qFAAqF;AACrF,qFAAqF;AACrF,qDAAqD;AACrD,MAAM,QAAQ,GAAG,yBAAyB,CAAC;AAC3C,MAAM,WAAW,GAAG,GAAG,CAAC;AACxB,MAAM,MAAM,GAAG,0BAA0B,CAAC;AAE1C,IAAI,MAAM,GAAG,KAAK,CAAC;AACnB,IAAI,SAAS,GAAkB,IAAI,CAAC;AAEpC,iEAAiE;AACjE,SAAS,SAAS,CAAC,CAAS;IAC3B,MAAM,MAAM,GAAI,UAA2D,CAAC,GAAG,CAAC;IAChF,IAAI,MAAM,EAAE,MAAM;QAAE,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAC5C,OAAO,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;AACpC,CAAC;AAED,SAAS,OAAO;IACf,IAAI,OAAO,QAAQ,KAAK,WAAW;QAAE,OAAO,IAAI,CAAC;IACjD,IAAI,EAAE,GAAG,QAAQ,CAAC,cAAc,CAAC,QAAQ,CAA4B,CAAC;IACtE,IAAI,CAAC,EAAE,EAAE,CAAC;QACT,EAAE,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;QACrC,EAAE,CAAC,EAAE,GAAG,QAAQ,CAAC;QACjB,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;IAC/B,CAAC;IACD,OAAO,EAAE,CAAC;AACX,CAAC;AAED,SAAS,MAAM;IACd,MAAM,EAAE,GAAG,OAAO,EAAE,CAAC;IACrB,IAAI,CAAC,EAAE;QAAE,OAAO;IAChB,IAAI,CAAC,MAAM,EAAE,CAAC;QACb,EAAE,CAAC,WAAW,GAAG,EAAE,CAAC;QACpB,OAAO;IACR,CAAC;IACD,MAAM,GAAG,GAAG,SAAS,CAAC,CAAC,CAAC,wBAAwB,SAAS,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IAC/E,EAAE,CAAC,WAAW,GAAG,kBAAkB,GAAG,oBAAoB,WAAW,MAAM,MAAM,QAAQ,WAAW,MAAM,MAAM,GAAG,CAAC;AACrH,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,cAAc,CAAC,EAAW;IACzC,IAAI,MAAM,KAAK,EAAE;QAAE,OAAO;IAC1B,MAAM,GAAG,EAAE,CAAC;IACZ,MAAM,EAAE,CAAC;AACV,CAAC;AAED,qFAAqF;AACrF,MAAM,UAAU,eAAe,CAAC,EAAiB;IAChD,IAAI,SAAS,KAAK,EAAE;QAAE,OAAO;IAC7B,SAAS,GAAG,EAAE,CAAC;IACf,MAAM,EAAE,CAAC;AACV,CAAC;AAED;6EAC6E;AAC7E,MAAM,UAAU,iBAAiB,CAAC,EAAU;IAC3C,IAAI,SAAS,KAAK,EAAE;QAAE,eAAe,CAAC,IAAI,CAAC,CAAC;AAC7C,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,aAAa;IAC5B,MAAM,GAAG,KAAK,CAAC;IACf,SAAS,GAAG,IAAI,CAAC;IACjB,OAAO,EAAE,EAAE,MAAM,EAAE,CAAC;AACrB,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { PluginContext } from "@edv4h/usketch-shared";
2
+ /** Wire the viewport constraint. Returns a teardown. */
3
+ export declare function setupViewportLock(ctx: PluginContext): () => void;
4
+ //# sourceMappingURL=viewport-lock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"viewport-lock.d.ts","sourceRoot":"","sources":["../src/viewport-lock.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAA2B,aAAa,EAAY,MAAM,uBAAuB,CAAC;AAgE9F,wDAAwD;AACxD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,IAAI,CA0GhE"}
@@ -0,0 +1,172 @@
1
+ import { clampViewportToBounds } from "@edv4h/usketch-store";
2
+ import { cellWAutoOf, getDashboardConfig, gridSpecFromConfig, viewportLockOf, } from "./config-ops.js";
3
+ import { isDashboardConfig } from "./dashboard-config-shape.js";
4
+ import { repackBoardTransient, runGuarded } from "./dashboard-runtime.js";
5
+ import { spanOf } from "./grid.js";
6
+ import { allDashboardItems, dashboardItems } from "./items.js";
7
+ /** Measure the canvas area in CSS pixels, or null when unavailable. Prefers the
8
+ * largest `canvas-container` (a minimap tags one too); falls back to the window. */
9
+ function canvasSize() {
10
+ if (typeof document !== "undefined") {
11
+ let best = null;
12
+ for (const el of document.querySelectorAll('[data-testid="canvas-container"]')) {
13
+ const r = el.getBoundingClientRect();
14
+ if (r.width > 0 && r.height > 0 && (!best || r.width * r.height > best.width * best.height)) {
15
+ best = { width: r.width, height: r.height };
16
+ }
17
+ }
18
+ if (best)
19
+ return best;
20
+ }
21
+ if (typeof window !== "undefined" && window.innerWidth > 0) {
22
+ return { width: window.innerWidth, height: window.innerHeight };
23
+ }
24
+ return null;
25
+ }
26
+ /** The grid's total width in world units (padding + columns + gaps). */
27
+ function gridWidthWorld(spec) {
28
+ const cols = Math.max(1, Math.floor(spec.columns));
29
+ return 2 * spec.padding + cols * spec.cellW + (cols - 1) * spec.gap;
30
+ }
31
+ /** The cell width that makes the grid exactly fill `screenWidth` at 100% zoom, or
32
+ * null when it can't (too many columns / no room). */
33
+ function autoCellWidth(spec, screenWidth) {
34
+ const cols = Math.max(1, Math.floor(spec.columns));
35
+ const w = (screenWidth - 2 * spec.padding - (cols - 1) * spec.gap) / cols;
36
+ return Number.isFinite(w) && w > 0 ? w : null;
37
+ }
38
+ /** The scrollable content rectangle in world units: the grid origin (top-left) out
39
+ * to the far edges of all shapes (so you can't scroll into the empty space above /
40
+ * left of the grid, and stop at the right / bottom of the content). */
41
+ function contentBounds(store, spec) {
42
+ let right = spec.originX + gridWidthWorld(spec); // at least the grid's own width
43
+ let bottom = spec.originY + 2 * spec.padding + spec.cellH; // at least one row tall
44
+ for (const s of allDashboardItems(store)) {
45
+ if (s.x + s.width > right)
46
+ right = s.x + s.width;
47
+ if (s.y + s.height > bottom)
48
+ bottom = s.y + s.height;
49
+ }
50
+ return {
51
+ x: spec.originX,
52
+ y: spec.originY,
53
+ width: right + spec.padding - spec.originX,
54
+ height: bottom + spec.padding - spec.originY,
55
+ };
56
+ }
57
+ /** Wire the viewport constraint. Returns a teardown. */
58
+ export function setupViewportLock(ctx) {
59
+ // Raised while we write the auto cell-width, so our own config-change listener
60
+ // doesn't recurse.
61
+ let applyingAuto = false;
62
+ const constrain = (vp) => {
63
+ if (!viewportLockOf(ctx.store))
64
+ return vp;
65
+ const config = getDashboardConfig(ctx.store);
66
+ if (!config)
67
+ return vp;
68
+ const size = canvasSize();
69
+ if (!size)
70
+ return vp;
71
+ const spec = gridSpecFromConfig(config); // cellW already auto-fit by reapply
72
+ const bounds = contentBounds(ctx.store, spec);
73
+ if (cellWAutoOf(ctx.store)) {
74
+ // AUTO width: fit to screen → 100% zoom, x pinned at the grid's left edge,
75
+ // vertical scroll only.
76
+ const clamped = clampViewportToBounds({ x: -spec.originX, y: vp.y, zoom: 1 }, bounds, size);
77
+ return { x: -spec.originX, y: clamped.y, zoom: 1 };
78
+ }
79
+ // FIXED numeric width: 100% zoom, pan BOTH axes within the content bounds
80
+ // (horizontal scroll when the grid is wider than the screen).
81
+ return clampViewportToBounds({ x: vp.x, y: vp.y, zoom: 1 }, bounds, size);
82
+ };
83
+ ctx.store.setViewportConstraint(constrain);
84
+ /** When "auto" width is on, size the cell width so the grid fills the screen AND
85
+ * grow/shrink every item to its cell width (span preserved, height untouched),
86
+ * then repack — transiently (no undo entry, ignored by the reflow runtime).
87
+ * Independent of the scroll-limit: turning on "幅Auto" fits even when the
88
+ * scroll-limit is off. No-op when the width isn't auto. */
89
+ function applyAutoWidth() {
90
+ if (!cellWAutoOf(ctx.store))
91
+ return;
92
+ const config = getDashboardConfig(ctx.store);
93
+ const size = canvasSize();
94
+ if (!config || !size)
95
+ return;
96
+ const oldSpec = gridSpecFromConfig(config);
97
+ const autoW = autoCellWidth(oldSpec, size.width);
98
+ if (autoW === null)
99
+ return;
100
+ const newSpec = gridSpecFromConfig({ ...config, cellW: autoW });
101
+ applyingAuto = true;
102
+ try {
103
+ runGuarded(() => {
104
+ if (Math.abs(config.cellW - autoW) >= 0.5) {
105
+ ctx.store.updateShape(config.id, { cellW: autoW });
106
+ }
107
+ // Resize each item's WIDTH to its (preserved) column span under the new
108
+ // cell width; height stays (cell height isn't auto).
109
+ for (const s of dashboardItems(ctx.store)) {
110
+ const span = spanOf(s.width, s.height, oldSpec);
111
+ const newW = span.cols * newSpec.cellW + (span.cols - 1) * newSpec.gap;
112
+ if (Math.abs(s.width - newW) >= 0.5)
113
+ ctx.store.updateShape(s.id, { width: newW });
114
+ }
115
+ });
116
+ repackBoardTransient(ctx);
117
+ }
118
+ finally {
119
+ applyingAuto = false;
120
+ }
121
+ }
122
+ // Re-fit the auto width and re-commit whenever the lock/auto flags toggle, the
123
+ // config (columns / gap / padding) changes, or the canvas resizes.
124
+ const reapply = () => {
125
+ applyAutoWidth();
126
+ ctx.store.setViewport(ctx.store.getViewport());
127
+ };
128
+ // Coalesce resize-driven reapplies to one per frame (a window/observer resize
129
+ // fires a burst; each reapply repacks, so we don't want one per event).
130
+ let rafPending = false;
131
+ const scheduleReapply = () => {
132
+ if (rafPending)
133
+ return;
134
+ rafPending = true;
135
+ const run = () => {
136
+ rafPending = false;
137
+ reapply();
138
+ };
139
+ if (typeof requestAnimationFrame === "function")
140
+ requestAnimationFrame(run);
141
+ else
142
+ setTimeout(run, 16);
143
+ };
144
+ const offMutation = ctx.store.onMutation((event) => {
145
+ if (applyingAuto)
146
+ return; // ignore our own auto-width write
147
+ if (event.type === "shape:updated" && isDashboardConfig(event.payload.after))
148
+ reapply();
149
+ });
150
+ // Refit on canvas resize. Observe the canvas element when present, AND always
151
+ // listen to window resize — the container may not exist at setup, or may not
152
+ // track the window, so the window listener is the reliable fallback.
153
+ let resizeObserver = null;
154
+ if (typeof document !== "undefined" && typeof ResizeObserver !== "undefined") {
155
+ const el = document.querySelector('[data-testid="canvas-container"]');
156
+ if (el) {
157
+ resizeObserver = new ResizeObserver(scheduleReapply);
158
+ resizeObserver.observe(el);
159
+ }
160
+ }
161
+ const onWindowResize = typeof window !== "undefined" ? scheduleReapply : null;
162
+ if (onWindowResize)
163
+ window.addEventListener("resize", onWindowResize);
164
+ return () => {
165
+ offMutation();
166
+ resizeObserver?.disconnect();
167
+ if (onWindowResize)
168
+ window.removeEventListener("resize", onWindowResize);
169
+ ctx.store.setViewportConstraint(null);
170
+ };
171
+ }
172
+ //# sourceMappingURL=viewport-lock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"viewport-lock.js","sourceRoot":"","sources":["../src/viewport-lock.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@edv4h/usketch-plugin-dashboard",
3
+ "version": "0.2.0",
4
+ "type": "module",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "source": "./src/index.ts",
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "dependencies": {
15
+ "@edv4h/usketch-shared": "4.13.0",
16
+ "@edv4h/usketch-store": "3.6.0"
17
+ },
18
+ "peerDependencies": {
19
+ "react": ">=19"
20
+ },
21
+ "publishConfig": {
22
+ "access": "public"
23
+ },
24
+ "files": [
25
+ "dist",
26
+ "README.md"
27
+ ],
28
+ "license": "MIT",
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "git+https://github.com/EdV4H/usketch.git",
32
+ "directory": "plugins/usketch-plugin-dashboard"
33
+ },
34
+ "homepage": "https://github.com/EdV4H/usketch#readme",
35
+ "bugs": {
36
+ "url": "https://github.com/EdV4H/usketch/issues"
37
+ },
38
+ "devDependencies": {
39
+ "@types/react": "19.2.18",
40
+ "typescript": "7.0.2",
41
+ "vitest": "4.1.11"
42
+ },
43
+ "scripts": {
44
+ "build": "tsc -p tsconfig.json",
45
+ "typecheck": "tsc --noEmit",
46
+ "test": "vitest run --passWithNoTests",
47
+ "clean": "rm -rf dist"
48
+ }
49
+ }