@stephen-netu/design-system 0.2.1 → 0.2.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.
Files changed (187) hide show
  1. package/dist/b0-app-shell/clarification-overlay/ClarificationOverlay.svelte +10 -2
  2. package/dist/b0-app-shell/clarification-overlay/ClarificationOverlay.svelte.d.ts.map +1 -1
  3. package/dist/b0-app-shell/{command-bar/CommandBar.svelte → global-command-bar/GlobalCommandBar.svelte} +75 -75
  4. package/dist/b0-app-shell/{command-bar/CommandBar.svelte.d.ts → global-command-bar/GlobalCommandBar.svelte.d.ts} +6 -6
  5. package/dist/b0-app-shell/global-command-bar/GlobalCommandBar.svelte.d.ts.map +1 -0
  6. package/dist/b0-app-shell/index.d.ts +1 -1
  7. package/dist/b0-app-shell/index.d.ts.map +1 -1
  8. package/dist/b0-app-shell/index.js +1 -1
  9. package/dist/d0-data-viz/CheckpointPill.svelte +7 -2
  10. package/dist/d0-data-viz/CheckpointPill.svelte.d.ts.map +1 -1
  11. package/dist/d0-data-viz/theme-integration.d.ts +3 -3
  12. package/dist/d0-data-viz/theme-integration.js +3 -3
  13. package/dist/d0-data-viz/theme-integration.test.js +41 -0
  14. package/dist/demos/BspSizingInfographic.svelte +3 -32
  15. package/dist/editor/CodeEditor.test.js +38 -0
  16. package/dist/editor/FindReplaceDialog.svelte +32 -32
  17. package/dist/editor/MarkdownEditor.svelte +71 -58
  18. package/dist/editor/MarkdownEditor.svelte.d.ts.map +1 -1
  19. package/dist/editor/MarkdownEditor.test.js +38 -0
  20. package/dist/editor/components/CorrectionTooltip.svelte +0 -1
  21. package/dist/entity-graph-view/WorldView.svelte +1 -1
  22. package/dist/fabric/ai/ChatPanel.svelte +31 -31
  23. package/dist/fabric/ai/ResearchPanel.svelte +6 -3
  24. package/dist/fabric/ai/ResearchPanel.svelte.d.ts.map +1 -1
  25. package/dist/fabric/index.d.ts +4 -5
  26. package/dist/fabric/index.d.ts.map +1 -1
  27. package/dist/fabric/index.js +3 -3
  28. package/dist/fabric/input/{CommandBar.svelte → AppHeaderBar.svelte} +13 -13
  29. package/dist/fabric/input/{CommandBar.svelte.d.ts → AppHeaderBar.svelte.d.ts} +5 -5
  30. package/dist/fabric/input/AppHeaderBar.svelte.d.ts.map +1 -0
  31. package/dist/fabric/input/{CommandBar.test.js → AppHeaderBar.test.js} +9 -9
  32. package/dist/fabric/input/index.d.ts +2 -2
  33. package/dist/fabric/input/index.d.ts.map +1 -1
  34. package/dist/fabric/input/index.js +1 -1
  35. package/dist/fabric/layout/KanbanBoard.svelte +25 -155
  36. package/dist/fabric/layout/KanbanBoard.svelte.d.ts +2 -26
  37. package/dist/fabric/layout/KanbanBoard.svelte.d.ts.map +1 -1
  38. package/dist/fabric/layout/KanbanBoard.test.js +125 -10
  39. package/dist/fabric/layout/KanbanCard.svelte +27 -223
  40. package/dist/fabric/layout/KanbanCard.svelte.d.ts +2 -19
  41. package/dist/fabric/layout/KanbanCard.svelte.d.ts.map +1 -1
  42. package/dist/fabric/layout/KanbanColumn.svelte +41 -275
  43. package/dist/fabric/layout/KanbanColumn.svelte.d.ts +2 -22
  44. package/dist/fabric/layout/KanbanColumn.svelte.d.ts.map +1 -1
  45. package/dist/fabric/layout/index.d.ts +2 -5
  46. package/dist/fabric/layout/index.d.ts.map +1 -1
  47. package/dist/fabric/layout/index.js +1 -1
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js +4 -2
  50. package/dist/l0-layout/SectionSplitter.svelte +5 -5
  51. package/dist/l0-layout/block-writer/BlockItem.svelte +6 -4
  52. package/dist/l0-layout/card/CompactCard.svelte +4 -3
  53. package/dist/l0-layout/grant/GrantCard.svelte +15 -5
  54. package/dist/l0-layout/grant/GrantCard.svelte.d.ts.map +1 -1
  55. package/dist/l0-layout/index.d.ts +2 -0
  56. package/dist/l0-layout/index.d.ts.map +1 -1
  57. package/dist/l0-layout/index.js +1 -0
  58. package/dist/l0-layout/kanban/KanbanBoard.svelte +246 -29
  59. package/dist/l0-layout/kanban/KanbanBoard.svelte.d.ts +28 -2
  60. package/dist/l0-layout/kanban/KanbanBoard.svelte.d.ts.map +1 -1
  61. package/dist/l0-layout/kanban/KanbanCard.svelte +175 -150
  62. package/dist/l0-layout/kanban/KanbanCard.svelte.d.ts +16 -18
  63. package/dist/l0-layout/kanban/KanbanCard.svelte.d.ts.map +1 -1
  64. package/dist/l0-layout/kanban/KanbanColumn.svelte +152 -78
  65. package/dist/l0-layout/kanban/KanbanColumn.svelte.d.ts +28 -7
  66. package/dist/l0-layout/kanban/KanbanColumn.svelte.d.ts.map +1 -1
  67. package/dist/l0-layout/kanban/index.d.ts +6 -0
  68. package/dist/l0-layout/kanban/index.d.ts.map +1 -0
  69. package/dist/l0-layout/kanban/index.js +3 -0
  70. package/dist/n0-node-graph/Node.svelte +2 -2
  71. package/dist/n0-node-graph/NodePalette.svelte +2 -2
  72. package/dist/n1-flow-canvas/graph-state.test.js +69 -0
  73. package/dist/n1-flow-canvas/utils.test.js +116 -0
  74. package/dist/n3-force-graph/GraphTooltip.svelte +2 -2
  75. package/dist/n4-adaptive-manifold/AdaptiveManifold.svelte +12 -11
  76. package/dist/n4-adaptive-manifold/AdaptiveManifold.svelte.d.ts.map +1 -1
  77. package/dist/n4-adaptive-manifold/classifier.test.js +104 -0
  78. package/dist/n4-adaptive-manifold/n4-tokens.css +2 -2
  79. package/dist/p0-primitives/ThemeProvider.svelte +10 -11
  80. package/dist/p0-primitives/ThemeProvider.svelte.d.ts +1 -1
  81. package/dist/p0-primitives/ThemeProvider.svelte.d.ts.map +1 -1
  82. package/dist/p0-primitives/canvas-theme.d.ts +12 -0
  83. package/dist/p0-primitives/canvas-theme.d.ts.map +1 -1
  84. package/dist/p0-primitives/canvas-theme.js +10 -0
  85. package/dist/p0-primitives/index.d.ts +2 -1
  86. package/dist/p0-primitives/index.d.ts.map +1 -1
  87. package/dist/p0-primitives/index.js +1 -0
  88. package/dist/p0-primitives/theme-context.d.ts +9 -0
  89. package/dist/p0-primitives/theme-context.d.ts.map +1 -0
  90. package/dist/p0-primitives/theme-context.js +8 -0
  91. package/dist/p0-primitives/tokens/tokens.css +22 -11
  92. package/dist/p0-primitives/utils/index.d.ts +2 -2
  93. package/dist/p0-primitives/utils/index.d.ts.map +1 -1
  94. package/dist/s0-state/SyncStatus.svelte +1 -1
  95. package/dist/s0-state/ThemeStore.svelte.d.ts +3 -2
  96. package/dist/s0-state/ThemeStore.svelte.d.ts.map +1 -1
  97. package/dist/s0-state/ThemeStore.svelte.js +20 -1
  98. package/dist/s0-state/index.d.ts +0 -1
  99. package/dist/s0-state/index.d.ts.map +1 -1
  100. package/dist/s0-state/index.js +1 -0
  101. package/dist/s0-state/modal-stack-store.svelte.d.ts +25 -0
  102. package/dist/s0-state/modal-stack-store.svelte.d.ts.map +1 -1
  103. package/dist/s0-state/modal-stack-store.svelte.js +19 -0
  104. package/dist/showcase/Showcase.svelte +43 -34
  105. package/dist/showcase/Showcase.svelte.d.ts.map +1 -1
  106. package/dist/spatial/BspTilingCanvas.svelte +5 -5
  107. package/dist/spatial/BspTilingSimulation.test.js +88 -0
  108. package/dist/spatial/CameraController.test.js +120 -0
  109. package/dist/spatial/ForceCanvas.svelte +18 -13
  110. package/dist/spatial/ForceCanvas.svelte.d.ts.map +1 -1
  111. package/dist/spatial/ForceSimulation.svelte.d.ts.map +1 -1
  112. package/dist/spatial/ForceSimulation.svelte.js +32 -21
  113. package/dist/spatial/LodRenderer.svelte +14 -1
  114. package/dist/spatial/LodRenderer.svelte.d.ts.map +1 -1
  115. package/dist/spatial/SnapZoomCamera.svelte +23 -13
  116. package/dist/spatial/SnapZoomCamera.svelte.d.ts.map +1 -1
  117. package/dist/spatial/ZoneTiler.svelte +3 -2
  118. package/dist/spatial/d3-types.d.ts +31 -0
  119. package/dist/spatial/d3-types.d.ts.map +1 -0
  120. package/dist/spatial/d3-types.js +19 -0
  121. package/dist/ssr-import-clean.test.js +37 -0
  122. package/dist/t0-transport/fs.d.ts +12 -0
  123. package/dist/t0-transport/fs.d.ts.map +1 -0
  124. package/dist/t0-transport/fs.js +55 -0
  125. package/dist/t0-transport/index.d.ts +1 -0
  126. package/dist/t0-transport/index.d.ts.map +1 -1
  127. package/dist/t0-transport/index.js +1 -0
  128. package/dist/t0-transport/invoke.d.ts.map +1 -1
  129. package/dist/t0-transport/invoke.js +5 -2
  130. package/dist/t0-transport/quality.d.ts +12 -3
  131. package/dist/t0-transport/quality.d.ts.map +1 -1
  132. package/dist/t0-transport/quality.js +17 -4
  133. package/dist/t0-transport/substrate.svelte.d.ts +27 -0
  134. package/dist/t0-transport/substrate.svelte.d.ts.map +1 -0
  135. package/dist/t0-transport/substrate.svelte.js +49 -0
  136. package/dist/u0-primitives/LockIndicator.svelte +1 -1
  137. package/dist/u0-primitives/VerticalToolbar.svelte +1 -1
  138. package/dist/u0-primitives/accordion/Accordion.svelte +10 -9
  139. package/dist/u0-primitives/accordion/Accordion.svelte.d.ts +0 -7
  140. package/dist/u0-primitives/accordion/Accordion.svelte.d.ts.map +1 -1
  141. package/dist/u0-primitives/accordion/Accordion.test.js +5 -5
  142. package/dist/u0-primitives/badge/Badge.test.js +10 -10
  143. package/dist/u0-primitives/badge/ValidityBadge.test.js +9 -9
  144. package/dist/u0-primitives/button/Button.svelte +3 -1
  145. package/dist/u0-primitives/button/Button.svelte.d.ts +1 -0
  146. package/dist/u0-primitives/button/Button.svelte.d.ts.map +1 -1
  147. package/dist/u0-primitives/button/Button.test.js +11 -11
  148. package/dist/u0-primitives/card/Card.svelte +26 -20
  149. package/dist/u0-primitives/card/Card.svelte.d.ts.map +1 -1
  150. package/dist/u0-primitives/command-palette/CommandPalette.svelte +27 -0
  151. package/dist/u0-primitives/command-palette/CommandPalette.svelte.d.ts.map +1 -1
  152. package/dist/u0-primitives/command-palette/commandStore.svelte.d.ts.map +1 -1
  153. package/dist/u0-primitives/command-palette/commandStore.svelte.js +2 -1
  154. package/dist/u0-primitives/dropdown/Dropdown.test.js +1 -1
  155. package/dist/u0-primitives/index.d.ts +2 -0
  156. package/dist/u0-primitives/index.d.ts.map +1 -1
  157. package/dist/u0-primitives/index.js +1 -0
  158. package/dist/u0-primitives/input/Input.svelte +9 -0
  159. package/dist/u0-primitives/input/Input.svelte.d.ts.map +1 -1
  160. package/dist/u0-primitives/input/Input.test.js +1 -1
  161. package/dist/u0-primitives/modal/Modal.svelte +46 -23
  162. package/dist/u0-primitives/modal/Modal.svelte.d.ts.map +1 -1
  163. package/dist/u0-primitives/modal/Modal.test.js +63 -15
  164. package/dist/u0-primitives/rsvp/RsvpReader.svelte +8 -8
  165. package/dist/u0-primitives/rsvp/RsvpReader.svelte.d.ts.map +1 -1
  166. package/dist/u0-primitives/steps/Steps.svelte +2 -2
  167. package/dist/u0-primitives/surface-state/SurfaceState.svelte +190 -0
  168. package/dist/u0-primitives/surface-state/SurfaceState.svelte.d.ts +15 -0
  169. package/dist/u0-primitives/surface-state/SurfaceState.svelte.d.ts.map +1 -0
  170. package/dist/u0-primitives/toggle/Toggle.svelte +12 -2
  171. package/dist/u0-primitives/tooltip/Tooltip.test.js +12 -12
  172. package/dist/v0-diagrams/MarkmapDiagram.test.js +49 -0
  173. package/dist/v0-diagrams/MermaidDiagram.svelte +21 -9
  174. package/dist/v0-diagrams/MermaidDiagram.svelte.d.ts.map +1 -1
  175. package/dist/v0-diagrams/MermaidDiagram.test.js +40 -0
  176. package/package.json +50 -24
  177. package/src/n4-adaptive-manifold/n4-tokens.css +2 -2
  178. package/src/p0-primitives/tokens/tokens.css +22 -11
  179. package/src/p0-primitives/tokens/tokens.json +13 -2
  180. package/dist/b0-app-shell/command-bar/CommandBar.svelte.d.ts.map +0 -1
  181. package/dist/fabric/input/CommandBar.svelte.d.ts.map +0 -1
  182. package/dist/stores/vaultStore.svelte +0 -14
  183. package/dist/stores/vaultStore.svelte.d.ts +0 -24
  184. package/dist/stores/vaultStore.svelte.d.ts.map +0 -1
  185. package/dist/tauri/index.d.ts +0 -3
  186. package/dist/tauri/index.d.ts.map +0 -1
  187. package/dist/tauri/index.js +0 -11
@@ -1,122 +1,169 @@
1
1
  <script lang="ts">
2
+ /**
3
+ * KanbanColumn — Merged canonical component.
4
+ *
5
+ * Combines fabric's ColumnState props pattern with l0's Snippet children,
6
+ * Badge composition, WIP limit, and ds-kanban-* CSS classes.
7
+ *
8
+ * @package @kos/design-system/fabric/layout
9
+ */
2
10
  import type { Snippet } from 'svelte';
3
- import Badge from '../../u0-primitives/badge/Badge.svelte';
11
+ import type { CardData } from './KanbanCard.svelte';
4
12
 
5
- interface Props {
13
+ export interface ColumnData {
6
14
  id: string;
7
15
  title: string;
8
- count?: number;
16
+ color?: string;
9
17
  wipLimit?: number;
10
- isOverLimit?: boolean;
18
+ }
19
+
20
+ export interface Props {
21
+ column: ColumnData;
22
+ isDropTarget?: boolean;
23
+ isCollapsed?: boolean;
24
+ isMoveTarget?: boolean;
25
+ onCardClick?: (card: CardData) => void;
26
+ onCardDragStart?: (card: CardData) => void;
27
+ onCardDragEnd?: () => void;
28
+ onDrop?: (targetColumnId: string, cardId: string) => void;
29
+ onDragOver?: (columnId: string) => void;
30
+ onDragLeave?: (columnId: string) => void;
31
+ onAddCard?: (columnId: string) => void;
32
+ onMenuClick?: (columnId: string) => void;
33
+ onCardKeyDown?: (e: KeyboardEvent, cardId: string, sourceColumnId: string) => void;
34
+ moveMode?: boolean;
35
+ children?: Snippet;
36
+ actions?: Snippet;
11
37
  class?: string;
12
- ondragover?: (e: DragEvent) => void;
13
- ondragleave?: (e: DragEvent) => void;
14
- ondrop?: (e: DragEvent) => void;
15
- children?: Snippet; // The KanbanCards go here
16
- actions?: Snippet; // Additional header actions (e.g. + button)
17
38
  }
18
39
 
19
40
  let {
20
- id,
21
- title,
22
- count = 0,
23
- wipLimit,
24
- isOverLimit = false,
25
- class: className = '',
26
- ondragover,
27
- ondragleave,
28
- ondrop,
41
+ column,
42
+ isDropTarget = false,
43
+ isCollapsed = false,
44
+ isMoveTarget = false,
45
+ onCardClick,
46
+ onCardDragStart,
47
+ onCardDragEnd,
48
+ onDrop,
49
+ onDragOver,
50
+ onDragLeave,
51
+ onAddCard,
52
+ onMenuClick,
53
+ onCardKeyDown,
54
+ moveMode = false,
29
55
  children,
30
- actions
56
+ actions,
57
+ class: className = '',
31
58
  }: Props = $props();
32
59
 
33
60
  let isDragTarget = $state(false);
34
61
 
35
- // Derived state for WIP limit
36
- let overLimit = $derived(isOverLimit || (wipLimit !== undefined && count > wipLimit));
37
-
38
62
  function handleDragOver(e: DragEvent) {
39
- e.preventDefault(); // Necessary to allow dropping
63
+ e.preventDefault();
40
64
  if (e.dataTransfer) {
41
65
  e.dataTransfer.dropEffect = 'move';
42
66
  }
43
67
  isDragTarget = true;
44
- ondragover?.(e);
68
+ onDragOver?.(column.id);
45
69
  }
46
70
 
47
71
  function handleDragLeave(e: DragEvent) {
48
72
  isDragTarget = false;
49
- ondragleave?.(e);
73
+ onDragLeave?.(column.id);
50
74
  }
51
75
 
52
76
  function handleDrop(e: DragEvent) {
53
77
  e.preventDefault();
54
78
  isDragTarget = false;
55
- ondrop?.(e);
79
+ const cardId = e.dataTransfer?.getData('text/plain');
80
+ if (cardId) {
81
+ onDrop?.(column.id, cardId);
82
+ }
56
83
  }
57
84
  </script>
58
85
 
59
- <div
86
+ <div
60
87
  class="ds-kanban-column {className}"
61
- class:is-over-limit={overLimit}
62
- data-column-id={id}
88
+ class:is-move-target={isMoveTarget}
89
+ data-column-id={column.id}
63
90
  >
64
91
  <header class="ds-kanban-column-header">
65
92
  <div class="ds-kanban-column-title-group">
66
- <h3 class="ds-kanban-column-title">{title}</h3>
67
- <Badge
68
- variant={overLimit ? 'status' : 'outline'}
69
- color={overLimit ? 'error' : 'neutral'}
70
- size="sm"
71
- >
72
- {count} {#if wipLimit}/ {wipLimit}{/if}
73
- </Badge>
93
+ {#if column.color}
94
+ <span
95
+ class="ds-kanban-column-color"
96
+ style="background: {column.color}"
97
+ ></span>
98
+ {/if}
99
+ <h3 class="ds-kanban-column-title">{column.title}</h3>
74
100
  </div>
75
101
 
76
- {#if actions}
77
- <div class="ds-kanban-column-actions">
102
+ <div class="ds-kanban-column-actions">
103
+ {#if actions}
78
104
  {@render actions()}
79
- </div>
80
- {/if}
81
- </header>
82
-
83
- <div
84
- class="ds-kanban-column-content"
85
- class:is-drag-target={isDragTarget}
86
- role="region"
87
- aria-label={`${title} column`}
88
- ondragover={handleDragOver}
89
- ondragleave={handleDragLeave}
90
- ondrop={handleDrop}
91
- >
92
- <div class="ds-kanban-column-scroll-area">
93
- {#if children}
94
- {@render children()}
105
+ {/if}
106
+ {#if onAddCard}
107
+ <button
108
+ class="ds-kanban-column-add-btn"
109
+ onclick={() => onAddCard?.(column.id)}
110
+ title="Add card"
111
+ aria-label={`Add card to ${column.title}`}
112
+ >
113
+ +
114
+ </button>
115
+ {/if}
116
+ {#if onMenuClick}
117
+ <button
118
+ class="ds-kanban-column-menu-btn"
119
+ onclick={() => onMenuClick?.(column.id)}
120
+ title="Column menu"
121
+ aria-label={`Menu for ${column.title}`}
122
+ >
123
+
124
+ </button>
95
125
  {/if}
96
126
  </div>
127
+ </header>
128
+
129
+ {#if !isCollapsed}
130
+ <div
131
+ class="ds-kanban-column-content"
132
+ class:is-drag-target={isDropTarget || isDragTarget}
133
+ role="region"
134
+ aria-label={`${column.title} column`}
135
+ ondragover={handleDragOver}
136
+ ondragleave={handleDragLeave}
137
+ ondrop={handleDrop}
138
+ >
139
+ <div class="ds-kanban-column-scroll-area">
140
+ {#if children}
141
+ {@render children()}
142
+ {/if}
143
+ </div>
97
144
 
98
- <!-- Drop indicator overlay -->
99
- <div class="ds-kanban-drop-indicator"></div>
100
- </div>
145
+ <div class="ds-kanban-drop-indicator"></div>
146
+ </div>
147
+ {/if}
101
148
  </div>
102
149
 
103
150
  <style>
104
151
  .ds-kanban-column {
105
152
  display: flex;
106
153
  flex-direction: column;
107
- min-width: 320px;
108
- max-width: 360px;
154
+ min-width: 18.75rem;
155
+ max-width: 22.5rem;
109
156
  height: 100%;
110
157
  background: var(--color-bg-panel);
111
- border-radius: var(--radius-lg);
112
- border: 1px solid var(--border-default);
158
+ border-radius: var(--radius-lg, 0.5rem);
159
+ border: var(--border-width-thin) solid var(--border-default);
113
160
  flex-shrink: 0;
114
- transition: border-color var(--transition-normal);
161
+ transition: border-color var(--transition-normal, 0.2s);
115
162
  }
116
163
 
117
- .ds-kanban-column.is-over-limit {
118
- border-color: rgba(166, 94, 94, 0.4);
119
- box-shadow: 0 0 0 1px rgba(166, 94, 94, 0.1) inset;
164
+ .ds-kanban-column.is-move-target {
165
+ border-color: var(--color-accent);
166
+ box-shadow: 0 0 0 var(--border-width-thin) var(--color-accent);
120
167
  }
121
168
 
122
169
  .ds-kanban-column-header {
@@ -124,13 +171,21 @@
124
171
  align-items: center;
125
172
  justify-content: space-between;
126
173
  padding: var(--space-4);
127
- border-bottom: 1px solid var(--border-subtle);
174
+ border-bottom: var(--border-width-thin) solid var(--border-subtle);
175
+ flex-shrink: 0;
128
176
  }
129
177
 
130
178
  .ds-kanban-column-title-group {
131
179
  display: flex;
132
180
  align-items: center;
133
- gap: var(--space-3);
181
+ gap: var(--space-2);
182
+ }
183
+
184
+ .ds-kanban-column-color {
185
+ width: var(--space-2);
186
+ height: var(--space-2);
187
+ border-radius: 50%;
188
+ flex-shrink: 0;
134
189
  }
135
190
 
136
191
  .ds-kanban-column-title {
@@ -143,7 +198,29 @@
143
198
  .ds-kanban-column-actions {
144
199
  display: flex;
145
200
  align-items: center;
146
- gap: var(--space-2);
201
+ gap: var(--space-1);
202
+ }
203
+
204
+ .ds-kanban-column-add-btn,
205
+ .ds-kanban-column-menu-btn {
206
+ display: flex;
207
+ align-items: center;
208
+ justify-content: center;
209
+ background: transparent;
210
+ border: none;
211
+ color: var(--color-text-tertiary);
212
+ padding: var(--space-1);
213
+ border-radius: var(--radius-sm, 0.25rem);
214
+ cursor: pointer;
215
+ font-size: var(--text-base);
216
+ line-height: 1;
217
+ transition: color 0.15s, background 0.15s;
218
+ }
219
+
220
+ .ds-kanban-column-add-btn:hover,
221
+ .ds-kanban-column-menu-btn:hover {
222
+ color: var(--color-text-secondary);
223
+ background: var(--color-bg-canvas);
147
224
  }
148
225
 
149
226
  .ds-kanban-column-content {
@@ -151,9 +228,8 @@
151
228
  flex: 1;
152
229
  display: flex;
153
230
  flex-direction: column;
154
- min-height: 100px;
155
- background: transparent;
156
- transition: background var(--transition-fast);
231
+ min-height: 5rem;
232
+ transition: background var(--transition-fast, 0.15s);
157
233
  }
158
234
 
159
235
  .ds-kanban-column-scroll-area {
@@ -165,9 +241,8 @@
165
241
  height: 100%;
166
242
  }
167
243
 
168
- /* Custom scrollbar for column */
169
244
  .ds-kanban-column-scroll-area::-webkit-scrollbar {
170
- width: 6px;
245
+ width: var(--size-divider);
171
246
  }
172
247
  .ds-kanban-column-scroll-area::-webkit-scrollbar-thumb {
173
248
  background: rgba(255, 255, 255, 0.1);
@@ -177,19 +252,18 @@
177
252
  background: transparent;
178
253
  }
179
254
 
180
- /* Drag Target State */
181
255
  .ds-kanban-column-content.is-drag-target {
182
- background: var(--color-accent-faint); /* Very subtle brass tint */
256
+ background: var(--color-accent-faint, rgba(184,115,51,0.06));
183
257
  }
184
258
 
185
259
  .ds-kanban-drop-indicator {
186
260
  position: absolute;
187
261
  inset: var(--space-3);
188
- border: 2px dashed var(--color-accent);
262
+ border: var(--border-width-default) dashed var(--color-accent);
189
263
  border-radius: var(--radius-md);
190
264
  opacity: 0;
191
265
  pointer-events: none;
192
- transition: opacity var(--transition-fast);
266
+ transition: opacity var(--transition-fast, 0.15s);
193
267
  }
194
268
 
195
269
  .ds-kanban-column-content.is-drag-target .ds-kanban-drop-indicator {
@@ -1,16 +1,37 @@
1
+ /**
2
+ * KanbanColumn — Merged canonical component.
3
+ *
4
+ * Combines fabric's ColumnState props pattern with l0's Snippet children,
5
+ * Badge composition, WIP limit, and ds-kanban-* CSS classes.
6
+ *
7
+ * @package @kos/design-system/fabric/layout
8
+ */
1
9
  import type { Snippet } from 'svelte';
2
- interface Props {
10
+ import type { CardData } from './KanbanCard.svelte';
11
+ export interface ColumnData {
3
12
  id: string;
4
13
  title: string;
5
- count?: number;
14
+ color?: string;
6
15
  wipLimit?: number;
7
- isOverLimit?: boolean;
8
- class?: string;
9
- ondragover?: (e: DragEvent) => void;
10
- ondragleave?: (e: DragEvent) => void;
11
- ondrop?: (e: DragEvent) => void;
16
+ }
17
+ export interface Props {
18
+ column: ColumnData;
19
+ isDropTarget?: boolean;
20
+ isCollapsed?: boolean;
21
+ isMoveTarget?: boolean;
22
+ onCardClick?: (card: CardData) => void;
23
+ onCardDragStart?: (card: CardData) => void;
24
+ onCardDragEnd?: () => void;
25
+ onDrop?: (targetColumnId: string, cardId: string) => void;
26
+ onDragOver?: (columnId: string) => void;
27
+ onDragLeave?: (columnId: string) => void;
28
+ onAddCard?: (columnId: string) => void;
29
+ onMenuClick?: (columnId: string) => void;
30
+ onCardKeyDown?: (e: KeyboardEvent, cardId: string, sourceColumnId: string) => void;
31
+ moveMode?: boolean;
12
32
  children?: Snippet;
13
33
  actions?: Snippet;
34
+ class?: string;
14
35
  }
15
36
  declare const KanbanColumn: import("svelte").Component<Props, {}, "">;
16
37
  type KanbanColumn = ReturnType<typeof KanbanColumn>;
@@ -1 +1 @@
1
- {"version":3,"file":"KanbanColumn.svelte.d.ts","sourceRoot":"","sources":["../../../src/l0-layout/kanban/KanbanColumn.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAIpC,UAAU,KAAK;IACb,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,CAAC,CAAC,EAAE,SAAS,KAAK,IAAI,CAAC;IACpC,WAAW,CAAC,EAAE,CAAC,CAAC,EAAE,SAAS,KAAK,IAAI,CAAC;IACrC,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,SAAS,KAAK,IAAI,CAAC;IAChC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AA8EH,QAAA,MAAM,YAAY,2CAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"KanbanColumn.svelte.d.ts","sourceRoot":"","sources":["../../../src/l0-layout/kanban/KanbanColumn.svelte.ts"],"names":[],"mappings":"AAGA;;;;;;;KAOK;AACL,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAGlD,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,KAAK;IACpB,MAAM,EAAE,UAAU,CAAC;IACnB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,IAAI,CAAC;IACvC,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,IAAI,CAAC;IAC3C,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IAC3B,MAAM,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1D,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,WAAW,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,WAAW,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,aAAa,CAAC,EAAE,CAAC,CAAC,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,KAAK,IAAI,CAAC;IACnF,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAiGH,QAAA,MAAM,YAAY,2CAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
@@ -0,0 +1,6 @@
1
+ export { default as KanbanBoard } from './KanbanBoard.svelte';
2
+ export { default as KanbanColumn } from './KanbanColumn.svelte';
3
+ export { default as KanbanCard } from './KanbanCard.svelte';
4
+ export type { ColumnData } from './KanbanColumn.svelte';
5
+ export type { CardData } from './KanbanCard.svelte';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/l0-layout/kanban/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,YAAY,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACxD,YAAY,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { default as KanbanBoard } from './KanbanBoard.svelte';
2
+ export { default as KanbanColumn } from './KanbanColumn.svelte';
3
+ export { default as KanbanCard } from './KanbanCard.svelte';
@@ -243,7 +243,7 @@
243
243
  }
244
244
 
245
245
  .n0-node-label {
246
- fill: var(--color-text, #e8e0d0);
246
+ fill: var(--color-text-primary, #e8e0d0);
247
247
  font-family: system-ui, sans-serif;
248
248
  font-size: 13px;
249
249
  font-weight: 500;
@@ -262,7 +262,7 @@
262
262
  .n0-node-body {
263
263
  overflow: hidden;
264
264
  padding: 8px;
265
- color: var(--color-text, #e8e0d0);
265
+ color: var(--color-text-primary, #e8e0d0);
266
266
  font-family: system-ui, sans-serif;
267
267
  font-size: 13px;
268
268
  }
@@ -156,7 +156,7 @@
156
156
  border-right: 1px solid var(--n0-node-border);
157
157
  overflow: hidden;
158
158
  font-family: var(--font-mono, monospace);
159
- color: var(--color-text, #e8e0d0);
159
+ color: var(--color-text-primary, #e8e0d0);
160
160
  }
161
161
 
162
162
  .n0-palette-search {
@@ -172,7 +172,7 @@
172
172
  background: var(--n0-canvas-bg);
173
173
  border: 1px solid var(--n0-node-border);
174
174
  border-radius: var(--radius-sm, 4px);
175
- color: var(--color-text, #e8e0d0);
175
+ color: var(--color-text-primary, #e8e0d0);
176
176
  font-family: inherit;
177
177
  font-size: 0.8rem;
178
178
  outline: none;
@@ -0,0 +1,69 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
+ import { GraphState } from './graph-state.svelte';
3
+ beforeEach(() => {
4
+ vi.useFakeTimers();
5
+ });
6
+ afterEach(() => {
7
+ vi.useRealTimers();
8
+ });
9
+ describe('n1-flow-canvas/GraphState', () => {
10
+ it('initializes with empty positions', () => {
11
+ const gs = new GraphState();
12
+ expect(gs.positions.size).toBe(0);
13
+ expect(gs.bfsOrder).toEqual([]);
14
+ });
15
+ it('applyLayout sets positions and bfsOrder', () => {
16
+ const gs = new GraphState();
17
+ const positions = new Map([
18
+ ['n1', { id: 'n1', x: 10, y: 20, width: 100, height: 50 }],
19
+ ['n2', { id: 'n2', x: 200, y: 300, width: 80, height: 40 }],
20
+ ]);
21
+ gs.applyLayout({ positions, bfsOrder: ['n1', 'n2'] });
22
+ vi.advanceTimersByTime(5000);
23
+ expect(gs.positions.size).toBe(2);
24
+ expect(gs.bfsOrder).toEqual(['n1', 'n2']);
25
+ });
26
+ it('setFocusCenter updates focusCenterId', () => {
27
+ const gs = new GraphState();
28
+ gs.setFocusCenter('n1');
29
+ expect(gs.focusCenterId).toBe('n1');
30
+ });
31
+ it('setLayoutRoot updates layoutRootId', () => {
32
+ const gs = new GraphState();
33
+ gs.setLayoutRoot('n1');
34
+ expect(gs.layoutRootId).toBe('n1');
35
+ });
36
+ it('setLayoutRoot calls onLayoutRootChange callback', () => {
37
+ const gs = new GraphState();
38
+ const callback = vi.fn();
39
+ gs.onLayoutRootChange = callback;
40
+ gs.setLayoutRoot('n1');
41
+ expect(callback).toHaveBeenCalledWith('n1');
42
+ });
43
+ it('destroy cancels animation', () => {
44
+ const gs = new GraphState();
45
+ const positions = new Map([
46
+ ['n1', { id: 'n1', x: 10, y: 20, width: 100, height: 50 }],
47
+ ]);
48
+ gs.applyLayout({ positions, bfsOrder: ['n1'] });
49
+ gs.destroy();
50
+ // Should not throw
51
+ vi.advanceTimersByTime(5000);
52
+ });
53
+ it('new applyLayout replaces previous positions', () => {
54
+ const gs = new GraphState();
55
+ const positions1 = new Map([
56
+ ['n1', { id: 'n1', x: 10, y: 20, width: 100, height: 50 }],
57
+ ]);
58
+ gs.applyLayout({ positions: positions1, bfsOrder: ['n1'] });
59
+ vi.advanceTimersByTime(5000);
60
+ const positions2 = new Map([
61
+ ['n2', { id: 'n2', x: 50, y: 60, width: 80, height: 40 }],
62
+ ]);
63
+ gs.applyLayout({ positions: positions2, bfsOrder: ['n2'] });
64
+ vi.advanceTimersByTime(5000);
65
+ expect(gs.positions.size).toBe(1);
66
+ expect(gs.positions.has('n2')).toBe(true);
67
+ expect(gs.positions.has('n1')).toBe(false);
68
+ });
69
+ });
@@ -0,0 +1,116 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { nodeHitTest, domEventToCanvasCoords, parseMentionEdges, parseGroupedSequenceEdges, } from './utils';
3
+ describe('n1-flow-canvas/utils', () => {
4
+ describe('nodeHitTest', () => {
5
+ it('returns node id when point is inside a node rect', () => {
6
+ const positions = new Map([
7
+ ['n1', { id: 'n1', x: 10, y: 20, width: 100, height: 50 }],
8
+ ['n2', { id: 'n2', x: 200, y: 200, width: 80, height: 40 }],
9
+ ]);
10
+ expect(nodeHitTest(50, 40, positions)).toBe('n1');
11
+ });
12
+ it('returns null when point is outside all nodes', () => {
13
+ const positions = new Map([
14
+ ['n1', { id: 'n1', x: 10, y: 20, width: 100, height: 50 }],
15
+ ]);
16
+ expect(nodeHitTest(500, 500, positions)).toBeNull();
17
+ });
18
+ it('returns null for empty positions map', () => {
19
+ expect(nodeHitTest(50, 50, new Map())).toBeNull();
20
+ });
21
+ it('returns first matching node for overlapping rects', () => {
22
+ const positions = new Map();
23
+ positions.set('a', { id: 'a', x: 0, y: 0, width: 100, height: 100 });
24
+ positions.set('b', { id: 'b', x: 50, y: 50, width: 100, height: 100 });
25
+ const result = nodeHitTest(60, 60, positions);
26
+ expect(result).toBe('a');
27
+ });
28
+ });
29
+ describe('domEventToCanvasCoords', () => {
30
+ it('converts DOM event to canvas pixel coordinates', () => {
31
+ const mockEvent = {
32
+ clientX: 100,
33
+ clientY: 200,
34
+ currentTarget: {
35
+ getBoundingClientRect: () => ({
36
+ left: 50,
37
+ top: 100,
38
+ width: 200,
39
+ height: 400,
40
+ }),
41
+ },
42
+ };
43
+ const coords = domEventToCanvasCoords(mockEvent, 800, 1600);
44
+ expect(coords.x).toBe(200);
45
+ expect(coords.y).toBe(400);
46
+ });
47
+ it('handles identity scale (1:1)', () => {
48
+ const mockEvent = {
49
+ clientX: 150,
50
+ clientY: 250,
51
+ currentTarget: {
52
+ getBoundingClientRect: () => ({
53
+ left: 50,
54
+ top: 50,
55
+ width: 800,
56
+ height: 600,
57
+ }),
58
+ },
59
+ };
60
+ const coords = domEventToCanvasCoords(mockEvent, 800, 600);
61
+ expect(coords.x).toBe(100);
62
+ expect(coords.y).toBe(200);
63
+ });
64
+ });
65
+ describe('parseMentionEdges', () => {
66
+ it('parses edges from description mentions', () => {
67
+ const items = [
68
+ { id: 'wt-1', description: 'Depends on wt-2 for setup' },
69
+ { id: 'wt-2', description: 'No deps' },
70
+ ];
71
+ const edges = parseMentionEdges(items, (t) => t.id, (t) => t.description ?? '', /wt-(\d+)/g, (m) => `wt-${m}`);
72
+ expect(edges.size).toBe(1);
73
+ expect(edges.has('wt-1->wt-2')).toBe(true);
74
+ });
75
+ it('returns empty map for items with no mentions', () => {
76
+ const items = [
77
+ { id: 'wt-1', description: 'No references here' },
78
+ { id: 'wt-2', description: 'Also none' },
79
+ ];
80
+ const edges = parseMentionEdges(items, (t) => t.id, (t) => t.description ?? '', /wt-(\d+)/g, (m) => `wt-${m}`);
81
+ expect(edges.size).toBe(0);
82
+ });
83
+ it('skips mentions to unknown ids', () => {
84
+ const items = [
85
+ { id: 'wt-1', description: 'Depends on wt-999' },
86
+ ];
87
+ const edges = parseMentionEdges(items, (t) => t.id, (t) => t.description ?? '', /wt-(\d+)/g, (m) => `wt-${m}`);
88
+ expect(edges.size).toBe(0);
89
+ });
90
+ });
91
+ describe('parseGroupedSequenceEdges', () => {
92
+ it('chains items sharing the same group key', () => {
93
+ const items = [
94
+ { id: 'a', domain: 'x', workspace: 'w1', createdAt: '2024-01-01' },
95
+ { id: 'b', domain: 'x', workspace: 'w1', createdAt: '2024-01-02' },
96
+ { id: 'c', domain: 'x', workspace: 'w1', createdAt: '2024-01-03' },
97
+ ];
98
+ const edges = parseGroupedSequenceEdges(items, (t) => t.id, (t) => `${t.domain}:${t.workspace}`, (t) => t.createdAt);
99
+ expect(edges.size).toBe(2);
100
+ expect(edges.has('a->b')).toBe(true);
101
+ expect(edges.has('b->c')).toBe(true);
102
+ });
103
+ it('returns empty map for single-item groups', () => {
104
+ const items = [
105
+ { id: 'a', domain: 'x', workspace: 'w1', createdAt: '2024-01-01' },
106
+ { id: 'b', domain: 'y', workspace: 'w2', createdAt: '2024-01-01' },
107
+ ];
108
+ const edges = parseGroupedSequenceEdges(items, (t) => t.id, (t) => `${t.domain}:${t.workspace}`, (t) => t.createdAt);
109
+ expect(edges.size).toBe(0);
110
+ });
111
+ it('handles empty input', () => {
112
+ const edges = parseGroupedSequenceEdges([], (t) => t.id, (t) => t.group, (t) => t.sort);
113
+ expect(edges.size).toBe(0);
114
+ });
115
+ });
116
+ });
@@ -70,12 +70,12 @@
70
70
  z-index: 1000;
71
71
  pointer-events: none;
72
72
 
73
- background: var(--bg-elevated, #2a2a2a);
73
+ background: var(--color-bg-elevated, #2a2a2a);
74
74
  border: 1px solid var(--border-subtle, rgba(255, 255, 255, 0.06));
75
75
  border-radius: var(--radius-sm, 6px);
76
76
  padding: var(--space-2, 0.5rem) var(--space-3, 0.75rem);
77
77
 
78
- color: var(--text-primary, #f2efe9);
78
+ color: var(--color-text-primary, #f2efe9);
79
79
  font-family: var(--font-mono, 'JetBrains Mono', monospace);
80
80
  font-size: 0.75rem;
81
81
  line-height: 1.4;