@stephen-netu/design-system 0.1.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 (204) hide show
  1. package/README.md +66 -0
  2. package/package.json +130 -0
  3. package/src/b0-app-shell/clarification-overlay/ClarificationOverlay.svelte +221 -0
  4. package/src/b0-app-shell/clarification-overlay/index.ts +1 -0
  5. package/src/b0-app-shell/command-bar/CommandBar.svelte +565 -0
  6. package/src/b0-app-shell/index.ts +14 -0
  7. package/src/base.css +152 -0
  8. package/src/d0-data-viz/BarChart.svelte +236 -0
  9. package/src/d0-data-viz/CheckpointBar.svelte +574 -0
  10. package/src/d0-data-viz/CheckpointPill.svelte +297 -0
  11. package/src/d0-data-viz/MetricCard.svelte +159 -0
  12. package/src/d0-data-viz/SparkLine.svelte +66 -0
  13. package/src/d0-data-viz/StorageMap.svelte +182 -0
  14. package/src/d0-data-viz/Timeline.svelte +188 -0
  15. package/src/d0-data-viz/checkpoint-types.ts +162 -0
  16. package/src/d0-data-viz/d0-tokens.css +32 -0
  17. package/src/d0-data-viz/index.ts +58 -0
  18. package/src/d0-data-viz/storage-map-types.ts +142 -0
  19. package/src/d0-data-viz/theme-integration.ts +134 -0
  20. package/src/d0-data-viz/types.ts +53 -0
  21. package/src/demos/BspSizingInfographic.svelte +386 -0
  22. package/src/demos/BspZoneDemo.svelte +255 -0
  23. package/src/demos/ControlRoomDemo.svelte +570 -0
  24. package/src/demos/NodepadBlocksShowcase.svelte +189 -0
  25. package/src/demos/index.ts +7 -0
  26. package/src/editor/CodeEditor.svelte +188 -0
  27. package/src/editor/FindReplaceDialog.svelte +516 -0
  28. package/src/editor/MarkdownEditor.svelte +660 -0
  29. package/src/editor/index.ts +2 -0
  30. package/src/entity-graph-view/WorldView.svelte +171 -0
  31. package/src/entity-graph-view/index.ts +6 -0
  32. package/src/entity-graph-view/types.ts +364 -0
  33. package/src/epistemic/index.ts +2 -0
  34. package/src/epistemic/types.ts +134 -0
  35. package/src/epistemic/utils.ts +32 -0
  36. package/src/f0-forms/checkbox/Checkbox.svelte +158 -0
  37. package/src/f0-forms/field/FormField.svelte +91 -0
  38. package/src/f0-forms/index.ts +11 -0
  39. package/src/f0-forms/radio/RadioGroup.svelte +192 -0
  40. package/src/f0-forms/search/SearchBar.svelte +99 -0
  41. package/src/f0-forms/select/Select.svelte +198 -0
  42. package/src/f0-forms/textarea/TextArea.svelte +170 -0
  43. package/src/f0-forms/toggle/FormToggle.svelte +147 -0
  44. package/src/f0-forms/validation/validate.ts +47 -0
  45. package/src/fabric/ai/ChatPanel.svelte +648 -0
  46. package/src/fabric/ai/index.ts +11 -0
  47. package/src/fabric/data/index.ts +21 -0
  48. package/src/fabric/feedback/StatusBar.svelte +274 -0
  49. package/src/fabric/feedback/ToastContainer.svelte +122 -0
  50. package/src/fabric/feedback/index.ts +14 -0
  51. package/src/fabric/index.ts +37 -0
  52. package/src/fabric/input/CommandBar.svelte +79 -0
  53. package/src/fabric/input/KeyboardShortcuts.svelte +388 -0
  54. package/src/fabric/input/index.ts +12 -0
  55. package/src/fabric/layout/GlassBox.svelte +193 -0
  56. package/src/fabric/layout/KanbanBoard.svelte +158 -0
  57. package/src/fabric/layout/KanbanCard.svelte +226 -0
  58. package/src/fabric/layout/KanbanColumn.svelte +278 -0
  59. package/src/fabric/layout/index.ts +17 -0
  60. package/src/fabric/navigation/ActivityRail.svelte +271 -0
  61. package/src/fabric/navigation/index.ts +11 -0
  62. package/src/g0-geo/SovereignMap.svelte +149 -0
  63. package/src/g0-geo/index.ts +2 -0
  64. package/src/index.ts +68 -0
  65. package/src/l0-layout/block-writer/BlockConnectionLines.svelte +98 -0
  66. package/src/l0-layout/block-writer/BlockContent.svelte +213 -0
  67. package/src/l0-layout/block-writer/BlockHeader.svelte +230 -0
  68. package/src/l0-layout/block-writer/BlockItem.svelte +177 -0
  69. package/src/l0-layout/block-writer/BlockWriter.svelte +219 -0
  70. package/src/l0-layout/block-writer/block-writer-types.ts +63 -0
  71. package/src/l0-layout/block-writer/index.ts +24 -0
  72. package/src/l0-layout/block-writer/markdown.ts +110 -0
  73. package/src/l0-layout/chat-view/ChatViewLayout.svelte +61 -0
  74. package/src/l0-layout/epistemic/AllayDetailPanel.svelte +113 -0
  75. package/src/l0-layout/epistemic/AssayDetailPanel.svelte +164 -0
  76. package/src/l0-layout/epistemic/AvenueTrace.svelte +253 -0
  77. package/src/l0-layout/epistemic/KnowledgeDetailPanel.svelte +204 -0
  78. package/src/l0-layout/epistemic/ParadigmLens.svelte +170 -0
  79. package/src/l0-layout/epistemic/ProvenanceChain.svelte +164 -0
  80. package/src/l0-layout/epistemic/TrustView.svelte +195 -0
  81. package/src/l0-layout/epistemic/index.ts +7 -0
  82. package/src/l0-layout/grove/AccordCard.svelte +156 -0
  83. package/src/l0-layout/grove/GroveCard.svelte +197 -0
  84. package/src/l0-layout/grove/MemberBadge.svelte +96 -0
  85. package/src/l0-layout/grove/MemberList.svelte +59 -0
  86. package/src/l0-layout/grove/grove-types.ts +29 -0
  87. package/src/l0-layout/grove/index.ts +14 -0
  88. package/src/l0-layout/index.ts +45 -0
  89. package/src/l0-layout/kanban/KanbanBoard.svelte +71 -0
  90. package/src/l0-layout/kanban/KanbanCard.svelte +276 -0
  91. package/src/l0-layout/kanban/KanbanColumn.svelte +198 -0
  92. package/src/l0-layout/kanban/KanbanViewLayout.svelte +61 -0
  93. package/src/l0-layout/workspace/WorkspaceLayout.svelte +93 -0
  94. package/src/n0-node-graph/GraphEditor.svelte +342 -0
  95. package/src/n0-node-graph/GraphHistory.svelte +122 -0
  96. package/src/n0-node-graph/Node.svelte +269 -0
  97. package/src/n0-node-graph/NodeCanvas.svelte +187 -0
  98. package/src/n0-node-graph/NodeEdge.svelte +152 -0
  99. package/src/n0-node-graph/NodePalette.svelte +318 -0
  100. package/src/n0-node-graph/NodePort.svelte +128 -0
  101. package/src/n0-node-graph/index.ts +33 -0
  102. package/src/n0-node-graph/n0-tokens.css +29 -0
  103. package/src/n0-node-graph/node-port-types.ts +19 -0
  104. package/src/n0-node-graph/types.ts +96 -0
  105. package/src/n0-node-graph/validate.test.ts +722 -0
  106. package/src/n0-node-graph/validate.ts +371 -0
  107. package/src/n1-flow-canvas/FlowCanvas.svelte +202 -0
  108. package/src/n1-flow-canvas/graph-state.svelte.ts +95 -0
  109. package/src/n1-flow-canvas/index.ts +21 -0
  110. package/src/n1-flow-canvas/layout.ts +118 -0
  111. package/src/n1-flow-canvas/layout.worker.ts +128 -0
  112. package/src/n1-flow-canvas/types.ts +102 -0
  113. package/src/n1-flow-canvas/utils.ts +146 -0
  114. package/src/n2-manifold-disk/ManifoldDisk.svelte +314 -0
  115. package/src/n2-manifold-disk/index.ts +6 -0
  116. package/src/n2-manifold-disk/poincare.ts +184 -0
  117. package/src/n3-force-graph/ForceGraph.svelte +180 -0
  118. package/src/n3-force-graph/GraphTooltip.svelte +99 -0
  119. package/src/n3-force-graph/animated-edge.ts +107 -0
  120. package/src/n3-force-graph/health-node.ts +128 -0
  121. package/src/n3-force-graph/index.ts +31 -0
  122. package/src/n3-force-graph/types.ts +94 -0
  123. package/src/n4-adaptive-manifold/AdaptiveManifold.svelte +1165 -0
  124. package/src/n4-adaptive-manifold/DetailCard.svelte +212 -0
  125. package/src/n4-adaptive-manifold/SuggestionIndicator.svelte +91 -0
  126. package/src/n4-adaptive-manifold/classifier.ts +139 -0
  127. package/src/n4-adaptive-manifold/index.ts +45 -0
  128. package/src/n4-adaptive-manifold/n4-tokens.css +155 -0
  129. package/src/n4-adaptive-manifold/orchestrator.ts +301 -0
  130. package/src/n4-adaptive-manifold/phase-theme.ts +92 -0
  131. package/src/n4-adaptive-manifold/pinnacle-events.ts +135 -0
  132. package/src/n4-adaptive-manifold/providers/gravitational-provider.ts +191 -0
  133. package/src/n4-adaptive-manifold/providers/manifold-provider.ts +276 -0
  134. package/src/n4-adaptive-manifold/transition.ts +90 -0
  135. package/src/n4-adaptive-manifold/types.ts +313 -0
  136. package/src/p0-primitives/index.ts +6 -0
  137. package/src/p0-primitives/tokens/control-room.css +309 -0
  138. package/src/p0-primitives/tokens/index.ts +6 -0
  139. package/src/p0-primitives/tokens/tokens.css +140 -0
  140. package/src/p0-primitives/tokens/tokens.json +132 -0
  141. package/src/p0-primitives/types/index.ts +123 -0
  142. package/src/p0-primitives/types/plugin-types.ts +74 -0
  143. package/src/p0-primitives/utils/index.ts +39 -0
  144. package/src/platform/hud-protocol.ts +20 -0
  145. package/src/platform/index.ts +3 -0
  146. package/src/s0-state/create-store.ts +84 -0
  147. package/src/s0-state/derived.ts +41 -0
  148. package/src/s0-state/index.ts +6 -0
  149. package/src/showcase/Showcase.svelte +401 -0
  150. package/src/spatial/BspTilingCanvas.svelte +232 -0
  151. package/src/spatial/ForceCanvas.svelte +289 -0
  152. package/src/spatial/LodRenderer.svelte +334 -0
  153. package/src/spatial/SnapZoomCamera.svelte +185 -0
  154. package/src/spatial/ZoneTiler.svelte +311 -0
  155. package/src/spatial/camera-types.ts +45 -0
  156. package/src/spatial/content-proportional-bsp.ts +253 -0
  157. package/src/spatial/force-canvas-types.ts +102 -0
  158. package/src/spatial/index.ts +15 -0
  159. package/src/spatial/lod-types.ts +70 -0
  160. package/src/spatial/zone-tiler-types.ts +177 -0
  161. package/src/stores/vaultStore.svelte +14 -0
  162. package/src/t0-transport/connection.ts +34 -0
  163. package/src/t0-transport/error.ts +37 -0
  164. package/src/t0-transport/events.ts +50 -0
  165. package/src/t0-transport/index.ts +6 -0
  166. package/src/t0-transport/invoke.ts +30 -0
  167. package/src/tauri/index.ts +13 -0
  168. package/src/u0-primitives/allay-gauge/AllayGauge.svelte +90 -0
  169. package/src/u0-primitives/allay-gauge/index.ts +1 -0
  170. package/src/u0-primitives/animated-icon/AnimatedIcon.svelte +273 -0
  171. package/src/u0-primitives/animated-icon/README.md +53 -0
  172. package/src/u0-primitives/animated-icon/index.ts +31 -0
  173. package/src/u0-primitives/assay-badge/AssayBadge.svelte +121 -0
  174. package/src/u0-primitives/assay-badge/AssaySignalBar.svelte +83 -0
  175. package/src/u0-primitives/assay-badge/index.ts +2 -0
  176. package/src/u0-primitives/avatar/Avatar.svelte +177 -0
  177. package/src/u0-primitives/badge/Badge.svelte +149 -0
  178. package/src/u0-primitives/button/Button.svelte +304 -0
  179. package/src/u0-primitives/card/Card.svelte +182 -0
  180. package/src/u0-primitives/dropdown/Dropdown.svelte +305 -0
  181. package/src/u0-primitives/expert-badge/ExpertBadge.svelte +89 -0
  182. package/src/u0-primitives/expert-badge/index.ts +1 -0
  183. package/src/u0-primitives/index.ts +35 -0
  184. package/src/u0-primitives/input/Input.svelte +237 -0
  185. package/src/u0-primitives/modal/Modal.svelte +331 -0
  186. package/src/u0-primitives/modal/index.ts +1 -0
  187. package/src/u0-primitives/spinner/Spinner.svelte +129 -0
  188. package/src/u0-primitives/tabs/Tabs.svelte +225 -0
  189. package/src/u0-primitives/tabs/tabs-types.ts +11 -0
  190. package/src/u0-primitives/toggle/Toggle.svelte +161 -0
  191. package/src/u0-primitives/tooltip/Tooltip.svelte +234 -0
  192. package/src/v0-diagrams/DiagramPanel.svelte +68 -0
  193. package/src/v0-diagrams/MarkmapDiagram.svelte +56 -0
  194. package/src/v0-diagrams/MermaidDiagram.svelte +53 -0
  195. package/src/v0-diagrams/index.ts +4 -0
  196. package/src/v0-diagrams/types.ts +28 -0
  197. package/src/v0-diagrams/v0-tokens.css +6 -0
  198. package/src/vite-env.d.ts +7 -0
  199. package/src/x0-enchanted-blocks/ENCHANTED_BLOCKS_SPEC.md +457 -0
  200. package/src/x0-enchanted-blocks/components/EnchantedBlock.svelte +485 -0
  201. package/src/x0-enchanted-blocks/components/NodepadBlock.svelte +262 -0
  202. package/src/x0-enchanted-blocks/core/block-layout.ts +211 -0
  203. package/src/x0-enchanted-blocks/core/block-types.ts +227 -0
  204. package/src/x0-enchanted-blocks/index.ts +46 -0
@@ -0,0 +1,271 @@
1
+ <script lang="ts">
2
+ /**
3
+ * ActivityRail - Fabric Component
4
+ *
5
+ * Vertical navigation rail for app switching and view selection.
6
+ * Decoupled from shell stores - uses props/callbacks for all state.
7
+ *
8
+ * @package @kos/design-system/fabric/navigation
9
+ * @adr 2026-04-12-leap-substrate-refactor-001
10
+ */
11
+ // Lucide icons are Svelte 4 class components - use permissive typing
12
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
13
+ type IconComponent = any;
14
+ import {
15
+ LayoutGrid, FileText, Network, Columns2, Globe,
16
+ FolderTree, MessageSquare, HelpCircle, Layers, Gauge, Wifi, Folder,
17
+ Compass, Cpu, MessageCircle, Inbox,
18
+ } from '@lucide/svelte';
19
+
20
+ export type RailItemType = 'app' | 'view' | 'panel';
21
+
22
+ export interface RailItem {
23
+ id: string;
24
+ type: RailItemType;
25
+ label: string;
26
+ iconName: string;
27
+ active?: boolean;
28
+ disabled?: boolean;
29
+ title?: string;
30
+ }
31
+
32
+ interface Props {
33
+ /** App-level items (top section) */
34
+ appItems: RailItem[];
35
+ /** View-level items (middle section) */
36
+ viewItems: RailItem[];
37
+ /** Panel toggle items (bottom section) */
38
+ panelItems: RailItem[];
39
+ /** Currently active app ID */
40
+ activeAppId?: string;
41
+ /** Callback when item is clicked */
42
+ onitemclick: (item: RailItem) => void;
43
+ /** Callback for help button */
44
+ onopenhelp?: () => void;
45
+ /** Enable drag-drop for stream cards (app items only) */
46
+ ondropstreamcard?: (item: RailItem, data: { content: string; contentType: string; source: string }) => void;
47
+ }
48
+
49
+ const props: Props = $props();
50
+
51
+ const ICON_MAP: Record<string, IconComponent> = {
52
+ 'layout-grid': LayoutGrid,
53
+ 'file-text': FileText,
54
+ 'network': Network,
55
+ 'columns': Columns2,
56
+ 'globe': Globe,
57
+ 'wifi': Wifi,
58
+ 'folder-tree': FolderTree,
59
+ 'message-square': MessageSquare,
60
+ 'folder': Folder,
61
+ 'compass': Compass,
62
+ 'cpu': Cpu,
63
+ 'message-circle': MessageCircle,
64
+ 'inbox': Inbox,
65
+ 'layers': Layers,
66
+ 'gauge': Gauge,
67
+ 'help-circle': HelpCircle,
68
+ };
69
+
70
+ function getIcon(name: string): IconComponent {
71
+ return ICON_MAP[name.toLowerCase()] ?? FileText;
72
+ }
73
+
74
+ // Drop target state
75
+ let dropTargetId = $state<string | null>(null);
76
+
77
+ function isStreamCardDrag(e: DragEvent): boolean {
78
+ return e.dataTransfer?.types.includes('application/json') ?? false;
79
+ }
80
+
81
+ function handleDragOver(item: RailItem, e: DragEvent) {
82
+ if (!isStreamCardDrag(e) || item.type !== 'app') return;
83
+ e.preventDefault();
84
+ if (e.dataTransfer) e.dataTransfer.dropEffect = 'copy';
85
+ dropTargetId = item.id;
86
+ }
87
+
88
+ function handleDragLeave(e: DragEvent) {
89
+ if (e.currentTarget instanceof HTMLElement && !e.currentTarget.contains(e.relatedTarget as Node)) {
90
+ dropTargetId = null;
91
+ }
92
+ }
93
+
94
+ function handleDrop(item: RailItem, e: DragEvent) {
95
+ e.preventDefault();
96
+ dropTargetId = null;
97
+ if (!props.ondropstreamcard || item.type !== 'app') return;
98
+
99
+ try {
100
+ const data = e.dataTransfer?.getData('application/json');
101
+ if (!data) return;
102
+ const payload = JSON.parse(data);
103
+ if (payload.type !== 'stream-card') return;
104
+
105
+ props.ondropstreamcard(
106
+ item,
107
+ { content: payload.content, contentType: payload.contentType, source: payload.source }
108
+ );
109
+ } catch {
110
+ // Not a valid stream card payload
111
+ }
112
+ }
113
+ </script>
114
+
115
+ <nav class="activity-rail" aria-label="Activity navigation">
116
+ <div class="rail-brand">⬡</div>
117
+
118
+ <!-- App buttons -->
119
+ <div class="rail-section rail-apps">
120
+ {#each props.appItems as item (item.id)}
121
+ {@const Icon = getIcon(item.iconName)}
122
+ <button
123
+ class="rail-btn"
124
+ class:active={item.active}
125
+ class:drag-over={dropTargetId === item.id}
126
+ class:disabled={item.disabled}
127
+ title={item.title ?? item.label}
128
+ aria-label={item.label}
129
+ onclick={() => props.onitemclick(item)}
130
+ ondragover={(e) => handleDragOver(item, e)}
131
+ ondragleave={handleDragLeave}
132
+ ondrop={(e) => handleDrop(item, e)}
133
+ >
134
+ <Icon size={18} />
135
+ </button>
136
+ {/each}
137
+ </div>
138
+
139
+ <div class="rail-divider"></div>
140
+
141
+ <!-- View buttons -->
142
+ <div class="rail-section">
143
+ {#each props.viewItems as item (item.id)}
144
+ {@const Icon = getIcon(item.iconName)}
145
+ <button
146
+ class="rail-btn"
147
+ class:active={item.active}
148
+ class:disabled={item.disabled}
149
+ title={item.label}
150
+ aria-label={item.label}
151
+ onclick={() => props.onitemclick(item)}
152
+ >
153
+ <Icon size={18} />
154
+ </button>
155
+ {/each}
156
+ </div>
157
+
158
+ <!-- Panel toggles -->
159
+ <div class="rail-section rail-panels">
160
+ {#each props.panelItems as item (item.id)}
161
+ {@const Icon = getIcon(item.iconName)}
162
+ <button
163
+ class="rail-btn"
164
+ class:active={item.active}
165
+ class:disabled={item.disabled}
166
+ title={item.label}
167
+ aria-label={item.label}
168
+ onclick={() => props.onitemclick(item)}
169
+ >
170
+ <Icon size={18} />
171
+ </button>
172
+ {/each}
173
+ </div>
174
+
175
+ <div class="rail-spacer"></div>
176
+
177
+ <button
178
+ class="rail-btn"
179
+ title="Keyboard shortcuts (?)"
180
+ aria-label="Keyboard shortcuts"
181
+ onclick={() => props.onopenhelp?.()}
182
+ >
183
+ <HelpCircle size={18} />
184
+ </button>
185
+ </nav>
186
+
187
+ <style>
188
+ .activity-rail {
189
+ display: flex;
190
+ flex-direction: column;
191
+ align-items: center;
192
+ width: 48px;
193
+ height: 100%;
194
+ background: var(--color-bg-canvas, #1a1a1a);
195
+ border-right: 1px solid var(--border-subtle, rgba(255,255,255,0.06));
196
+ padding: 4px 0;
197
+ gap: 2px;
198
+ }
199
+
200
+ .rail-brand {
201
+ display: flex;
202
+ align-items: center;
203
+ justify-content: center;
204
+ height: 36px;
205
+ color: var(--color-accent, #b87333);
206
+ font-size: 16px;
207
+ flex-shrink: 0;
208
+ margin-bottom: 4px;
209
+ }
210
+
211
+ .rail-section {
212
+ display: flex;
213
+ flex-direction: column;
214
+ align-items: center;
215
+ gap: 2px;
216
+ width: 100%;
217
+ }
218
+
219
+ .rail-divider {
220
+ width: 24px;
221
+ height: 1px;
222
+ background: var(--border-subtle, rgba(255,255,255,0.08));
223
+ margin: 4px 0;
224
+ }
225
+
226
+ .rail-panels {
227
+ border-top: 1px solid var(--border-subtle, rgba(255,255,255,0.06));
228
+ padding-top: 4px;
229
+ margin-top: 4px;
230
+ }
231
+
232
+ .rail-spacer {
233
+ flex: 1;
234
+ }
235
+
236
+ .rail-btn {
237
+ width: 36px;
238
+ height: 36px;
239
+ background: transparent;
240
+ border: none;
241
+ color: var(--color-text-tertiary, #706858);
242
+ cursor: pointer;
243
+ border-radius: var(--radius-lg, 0.5rem);
244
+ display: flex;
245
+ align-items: center;
246
+ justify-content: center;
247
+ transition: background 120ms, color 120ms, box-shadow 120ms;
248
+ flex-shrink: 0;
249
+ }
250
+
251
+ .rail-btn:hover {
252
+ background: rgba(255,255,255,0.05);
253
+ color: var(--color-text-secondary, #a09880);
254
+ }
255
+
256
+ .rail-btn.active {
257
+ background: var(--color-accent-subtle, rgba(184, 115, 51, 0.15));
258
+ color: var(--color-accent, #b87333);
259
+ }
260
+
261
+ .rail-btn.drag-over {
262
+ background: rgba(184, 115, 51, 0.25);
263
+ box-shadow: 0 0 8px rgba(184, 115, 51, 0.4);
264
+ color: var(--color-accent, #b87333);
265
+ }
266
+
267
+ .rail-btn.disabled {
268
+ opacity: 0.3;
269
+ pointer-events: none;
270
+ }
271
+ </style>
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Fabric Navigation Components
3
+ *
4
+ * Navigation patterns for app switching and view selection.
5
+ *
6
+ * @package @kos/design-system/fabric/navigation
7
+ * @adr 2026-04-12-leap-substrate-refactor-001
8
+ */
9
+
10
+ export { default as ActivityRail } from './ActivityRail.svelte';
11
+ export type { RailItem, RailItemType } from './ActivityRail.svelte';
@@ -0,0 +1,149 @@
1
+ <script lang="ts">
2
+ // SovereignMap — KOS-themed Leaflet map primitive.
3
+ //
4
+ // Design decisions (ADR: 2026-04-05-mir-civic-commons-adr.md):
5
+ // - Leaflet (BSD-2, 42KB gzipped) with CartoDB dark_all tiles — no API key required.
6
+ // - `visibility: hidden` persistence semantics: map is never destroyed when
7
+ // backgrounded (consistent with CodeMirror and canvas components in LEAP).
8
+ // - Long-term: regional PMTiles extract for offline sovereign operation.
9
+
10
+ import { onMount, onDestroy } from 'svelte';
11
+ import 'leaflet/dist/leaflet.css';
12
+
13
+ interface GeoPoint {
14
+ lat: number;
15
+ lon: number;
16
+ }
17
+
18
+ interface MapMarker {
19
+ id: string;
20
+ lat: number;
21
+ lon: number;
22
+ label: string;
23
+ selected?: boolean;
24
+ }
25
+
26
+ interface Props {
27
+ center: GeoPoint;
28
+ zoom?: number;
29
+ markers?: MapMarker[];
30
+ onMarkerSelect?: (id: string) => void;
31
+ }
32
+
33
+ let { center, zoom = 12, markers = [], onMarkerSelect }: Props = $props();
34
+
35
+ let mapEl: HTMLDivElement;
36
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
37
+ let map: any = null;
38
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
39
+ let markerLayer: any = null;
40
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
41
+ let L: any = null;
42
+
43
+ onMount(async () => {
44
+ // Dynamic import keeps Leaflet out of the critical bundle path.
45
+ // CSS is statically imported at top of file — resolved from node_modules at build time (ADR: 2026-04-05-sovereign-map-css-delivery-adr.md).
46
+ const leafletModule = await import('leaflet');
47
+ L = leafletModule.default;
48
+
49
+ map = L.map(mapEl).setView([center.lat, center.lon], zoom);
50
+
51
+ L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png', {
52
+ attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors &copy; <a href="https://carto.com/attributions">CARTO</a>',
53
+ subdomains: 'abcd',
54
+ maxZoom: 19,
55
+ }).addTo(map);
56
+
57
+ markerLayer = L.layerGroup().addTo(map);
58
+ syncMarkers();
59
+ });
60
+
61
+ onDestroy(() => {
62
+ map?.remove();
63
+ map = null;
64
+ });
65
+
66
+ // Reactively sync markers when prop changes.
67
+ $effect(() => {
68
+ if (map) syncMarkers();
69
+ });
70
+
71
+ // Reactively re-centre when center prop changes.
72
+ $effect(() => {
73
+ map?.setView([center.lat, center.lon], zoom);
74
+ });
75
+
76
+ function syncMarkers() {
77
+ if (!markerLayer || !L) return;
78
+ markerLayer.clearLayers();
79
+
80
+ for (const m of markers) {
81
+ const icon = L.divIcon({
82
+ className: '',
83
+ html: `<div class="sov-marker${m.selected ? ' sov-marker--selected' : ''}"></div>`,
84
+ iconSize: [12, 12],
85
+ iconAnchor: [6, 6],
86
+ });
87
+
88
+ const leafletMarker = L.marker([m.lat, m.lon], { icon }).addTo(markerLayer);
89
+ leafletMarker.bindTooltip(m.label, { permanent: false, direction: 'top' });
90
+
91
+ if (onMarkerSelect) {
92
+ const id = m.id;
93
+ leafletMarker.on('click', () => onMarkerSelect(id));
94
+ }
95
+ }
96
+ }
97
+ </script>
98
+
99
+ <div bind:this={mapEl} class="sovereign-map"></div>
100
+
101
+ <style>
102
+ .sovereign-map {
103
+ width: 100%;
104
+ height: 100%;
105
+ background: #1a1a1a;
106
+ }
107
+
108
+ /* Leaflet override: match KOS dark theme for controls */
109
+ :global(.leaflet-control-zoom a) {
110
+ background: #222;
111
+ border-color: #444;
112
+ color: #e8e0d0;
113
+ }
114
+
115
+ :global(.leaflet-control-zoom a:hover) {
116
+ background: #2a2a2a;
117
+ }
118
+
119
+ :global(.leaflet-control-attribution) {
120
+ background: rgba(26, 26, 26, 0.8);
121
+ color: #a09880;
122
+ font-size: 10px;
123
+ }
124
+
125
+ :global(.sov-marker) {
126
+ background: #b87333;
127
+ border: 2px solid #e8e0d0;
128
+ border-radius: 50%;
129
+ width: 10px;
130
+ height: 10px;
131
+ cursor: pointer;
132
+ transition: transform 0.1s;
133
+ }
134
+
135
+ :global(.sov-marker--selected) {
136
+ background: #e8e0d0;
137
+ border-color: #b87333;
138
+ transform: scale(1.4);
139
+ }
140
+
141
+ :global(.leaflet-tooltip) {
142
+ background: #222;
143
+ border: 1px solid #444;
144
+ color: #e8e0d0;
145
+ font-family: system-ui, sans-serif;
146
+ font-size: 12px;
147
+ padding: 4px 8px;
148
+ }
149
+ </style>
@@ -0,0 +1,2 @@
1
+ // G0 Geo — Geospatial map primitives
2
+ export { default as SovereignMap } from './SovereignMap.svelte';
package/src/index.ts ADDED
@@ -0,0 +1,68 @@
1
+ // LEAP Design System — HDA-organized frontend primitives
2
+ // @kos/design-system
3
+
4
+ // CSS imports
5
+ import './base.css';
6
+ import './p0-primitives/tokens/tokens.css';
7
+ import './p0-primitives/tokens/control-room.css';
8
+ import './n0-node-graph/n0-tokens.css';
9
+ import './d0-data-viz/d0-tokens.css';
10
+ import './n4-adaptive-manifold/n4-tokens.css';
11
+
12
+ // B0 App Shell — Global LEAP chrome (CommandBar, intent dispatch, system state)
13
+ // B = Base shell layer — free in both SOVEREIGN HDA and existing DS prefixes
14
+ export * from './b0-app-shell';
15
+
16
+ // P0 Primitives — Shared types, utilities, design tokens
17
+ export * from './p0-primitives';
18
+
19
+ // U0 Primitives — Atomic UI components
20
+ export * from './u0-primitives';
21
+
22
+ // L0 Layout — Layout compositions
23
+ export * from './l0-layout';
24
+
25
+ // S0 State — Store primitives (Svelte 5 runes)
26
+ export * from './s0-state';
27
+
28
+ // T0 Transport — Tauri IPC
29
+ export * from './t0-transport';
30
+
31
+ // F0 Forms — Form primitives
32
+ export * from './f0-forms';
33
+
34
+ // D0 Data Viz — Charts, metrics, timelines
35
+ export * from './d0-data-viz';
36
+
37
+ // N0 Node Graph — Visual composition primitives (SVG DAG, <100 nodes)
38
+ export * from './n0-node-graph';
39
+
40
+ // N1 Flow Canvas — Canvas 2D + ELK layout + BFS edge reveal (PS2 aesthetic)
41
+ export * from './n1-flow-canvas';
42
+
43
+ // N2 Manifold Disk — Poincaré disk projection, wraps N1
44
+ export * from './n2-manifold-disk';
45
+
46
+ // N3 Force Graph — Force-directed graph with health-aware rendering (force-graph)
47
+ export * from './n3-force-graph';
48
+
49
+ // N4 Adaptive Manifold — Unified topology-aware graph layout with classifier
50
+ export * from './n4-adaptive-manifold';
51
+
52
+ // Entity Graph View — SOVEREIGN entity graph visualization
53
+ export * from './entity-graph-view';
54
+
55
+ // Epistemic types
56
+ export * from './epistemic';
57
+
58
+ // Platform — cross-boundary protocols (HUD, etc.)
59
+ export * from './platform';
60
+
61
+ // Spatial — BSP zone tiling, force-directed layout, LOD rendering, snap-zoom camera
62
+ export * from './spatial';
63
+
64
+ // G0 Geo — Geospatial map primitives (SovereignMap)
65
+ export * from './g0-geo';
66
+
67
+ // X0 Enchanted Blocks — Adaptive spatial content with Pretext measurement
68
+ export * from './x0-enchanted-blocks';
@@ -0,0 +1,98 @@
1
+ <script lang="ts">
2
+ import type { BlockConnection } from './block-writer-types.js';
3
+ import type { ZoneRect } from '../../spatial/zone-tiler-types.js';
4
+
5
+ interface Props {
6
+ connections: BlockConnection[];
7
+ zones: ZoneRect[];
8
+ focusedBlockId?: string;
9
+ }
10
+
11
+ let { connections, zones, focusedBlockId = '' }: Props = $props();
12
+
13
+ interface LineSegment {
14
+ x1: number;
15
+ y1: number;
16
+ x2: number;
17
+ y2: number;
18
+ isActive: boolean;
19
+ label?: string;
20
+ }
21
+
22
+ const lines = $derived.by((): LineSegment[] => {
23
+ const zoneMap = new Map(zones.map(z => [z.id, z]));
24
+ const result: LineSegment[] = [];
25
+
26
+ for (const conn of connections) {
27
+ const from = zoneMap.get(conn.fromId);
28
+ const to = zoneMap.get(conn.toId);
29
+ if (!from || !to) continue;
30
+
31
+ result.push({
32
+ x1: from.x + from.width / 2,
33
+ y1: from.y + from.height,
34
+ x2: to.x + to.width / 2,
35
+ y2: to.y,
36
+ isActive: conn.fromId === focusedBlockId || conn.toId === focusedBlockId,
37
+ label: conn.label,
38
+ });
39
+ }
40
+
41
+ return result;
42
+ });
43
+ </script>
44
+
45
+ {#if lines.length > 0}
46
+ <svg class="ds-block-connections" xmlns="http://www.w3.org/2000/svg">
47
+ {#each lines as line (`${line.x1},${line.y1}-${line.x2},${line.y2}`)}
48
+ <line
49
+ x1={line.x1}
50
+ y1={line.y1}
51
+ x2={line.x2}
52
+ y2={line.y2}
53
+ class:ds-block-conn-active={line.isActive}
54
+ class="ds-block-conn-line"
55
+ />
56
+ {#if line.label}
57
+ <text
58
+ x={(line.x1 + line.x2) / 2}
59
+ y={(line.y1 + line.y2) / 2 - 4}
60
+ class="ds-block-conn-label"
61
+ >{line.label}</text>
62
+ {/if}
63
+ {/each}
64
+ </svg>
65
+ {/if}
66
+
67
+ <style>
68
+ .ds-block-connections {
69
+ position: absolute;
70
+ top: 0;
71
+ left: 0;
72
+ width: 100%;
73
+ height: 100%;
74
+ pointer-events: none;
75
+ z-index: 5;
76
+ }
77
+
78
+ .ds-block-conn-line {
79
+ stroke: var(--color-accent, #b87333);
80
+ stroke-opacity: 0.35;
81
+ stroke-width: 1.5;
82
+ stroke-dasharray: 4 3;
83
+ transition: stroke-opacity 0.15s ease, stroke-width 0.15s ease;
84
+ }
85
+
86
+ .ds-block-conn-active {
87
+ stroke-opacity: 0.7;
88
+ stroke-width: 2;
89
+ }
90
+
91
+ .ds-block-conn-label {
92
+ fill: var(--color-text-muted, #a09880);
93
+ font-size: 10px;
94
+ font-family: var(--font-mono, monospace);
95
+ text-anchor: middle;
96
+ pointer-events: none;
97
+ }
98
+ </style>