feat: add collapsible/expandable zones for canvas decluttering

- Add collapsed state to NodeData.custom_colors (type=groupRect only)
- Implement toggleNodeCollapsed action in canvasStore (Zustand)
- Extend GroupRectNode UI with smooth chevron toggle button
  - Rotating chevron icon (↓ → when collapsed)
  - Shows '+N' badge when zone is hidden
  - Reduces zone opacity to 0.6 when collapsed
  - All transitions target 60 FPS (ease-out 200ms)
- Filter child nodes/edges in CanvasContainer based on parent collapse state
  - Breadth-first traversal handles multi-level nesting
  - Connecting edges to hidden nodes are automatically hidden
- Add comprehensive test coverage
  - Store: toggleNodeCollapsed state mutation, unsaved flag
  - Component: chevron rendering, click handlers, opacity transitions
- Persist collapsed state via YAML serialization (part of custom_colors)

Benefits:
- Declutter large Zigbee meshes, multi-building networks
- Preserve layout structure without deleting nodes
- Smooth 60 FPS transitions for UX polish

CONTRIBUTING.md compliance:
- Strict TypeScript types, no 'any'
- Zustand store pattern, no prop drilling
- Tests for store logic and component behavior
- Frontend linting requirements met

Co-authored-by: CyberClaw <noreply@openclaw.ai>
This commit is contained in:
pranjal-joshi
2026-05-17 19:37:04 +00:00
parent d066f37e88
commit 525dfe5ece
7 changed files with 300 additions and 65 deletions
-63
View File
@@ -2520,9 +2520,6 @@
"arm"
],
"dev": true,
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
@@ -2537,9 +2534,6 @@
"arm"
],
"dev": true,
"libc": [
"musl"
],
"license": "MIT",
"optional": true,
"os": [
@@ -2554,9 +2548,6 @@
"arm64"
],
"dev": true,
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
@@ -2571,9 +2562,6 @@
"arm64"
],
"dev": true,
"libc": [
"musl"
],
"license": "MIT",
"optional": true,
"os": [
@@ -2588,9 +2576,6 @@
"loong64"
],
"dev": true,
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
@@ -2605,9 +2590,6 @@
"loong64"
],
"dev": true,
"libc": [
"musl"
],
"license": "MIT",
"optional": true,
"os": [
@@ -2622,9 +2604,6 @@
"ppc64"
],
"dev": true,
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
@@ -2639,9 +2618,6 @@
"ppc64"
],
"dev": true,
"libc": [
"musl"
],
"license": "MIT",
"optional": true,
"os": [
@@ -2656,9 +2632,6 @@
"riscv64"
],
"dev": true,
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
@@ -2673,9 +2646,6 @@
"riscv64"
],
"dev": true,
"libc": [
"musl"
],
"license": "MIT",
"optional": true,
"os": [
@@ -2690,9 +2660,6 @@
"s390x"
],
"dev": true,
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
@@ -2707,9 +2674,6 @@
"x64"
],
"dev": true,
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
@@ -2724,9 +2688,6 @@
"x64"
],
"dev": true,
"libc": [
"musl"
],
"license": "MIT",
"optional": true,
"os": [
@@ -2975,9 +2936,6 @@
"arm64"
],
"dev": true,
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
@@ -2995,9 +2953,6 @@
"arm64"
],
"dev": true,
"libc": [
"musl"
],
"license": "MIT",
"optional": true,
"os": [
@@ -3015,9 +2970,6 @@
"x64"
],
"dev": true,
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
@@ -3035,9 +2987,6 @@
"x64"
],
"dev": true,
"libc": [
"musl"
],
"license": "MIT",
"optional": true,
"os": [
@@ -6935,9 +6884,6 @@
"arm64"
],
"dev": true,
"libc": [
"glibc"
],
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -6959,9 +6905,6 @@
"arm64"
],
"dev": true,
"libc": [
"musl"
],
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -6983,9 +6926,6 @@
"x64"
],
"dev": true,
"libc": [
"glibc"
],
"license": "MPL-2.0",
"optional": true,
"os": [
@@ -7007,9 +6947,6 @@
"x64"
],
"dev": true,
"libc": [
"musl"
],
"license": "MPL-2.0",
"optional": true,
"os": [