@imenam/mcp-design 1.0.4 → 1.0.6

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 (47) hide show
  1. package/README.md +61 -8
  2. package/dist/shared/icons/icon-data.d.ts +2 -0
  3. package/dist/shared/icons/icon-data.js +5 -0
  4. package/dist/shared/icons/icon-keywords.d.ts +1 -0
  5. package/dist/shared/icons/icon-keywords.js +4 -0
  6. package/dist/shared/icons/index.d.ts +47 -0
  7. package/dist/shared/icons/index.js +107 -0
  8. package/dist/shared/icons/search.d.ts +31 -0
  9. package/dist/shared/icons/search.js +104 -0
  10. package/dist/shared/instances.d.ts +39 -0
  11. package/dist/shared/instances.js +94 -0
  12. package/dist/shared/node-defaults.d.ts +2 -0
  13. package/dist/shared/node-defaults.js +32 -4
  14. package/dist/shared/node-fields.d.ts +2 -0
  15. package/dist/shared/node-fields.js +17 -4
  16. package/dist/shared/render.d.ts +31 -1
  17. package/dist/shared/render.js +65 -6
  18. package/dist/shared/schemas/design.schema.d.ts +19 -1
  19. package/dist/shared/schemas/design.schema.js +13 -1
  20. package/dist/src/core/clone.d.ts +23 -0
  21. package/dist/src/core/clone.js +34 -0
  22. package/dist/src/core/diff.js +2 -2
  23. package/dist/src/core/export.js +63 -3
  24. package/dist/src/core/hierarchy.d.ts +7 -0
  25. package/dist/src/core/hierarchy.js +75 -5
  26. package/dist/src/core/node-factory.js +55 -5
  27. package/dist/src/core/screenshot.d.ts +12 -0
  28. package/dist/src/core/screenshot.js +17 -6
  29. package/dist/src/index.js +97 -7
  30. package/dist/src/tools/add-nodes.js +7 -1
  31. package/dist/src/tools/delete-nodes.js +10 -1
  32. package/dist/src/tools/detach-instances.d.ts +14 -0
  33. package/dist/src/tools/detach-instances.js +61 -0
  34. package/dist/src/tools/duplicate-nodes.js +20 -28
  35. package/dist/src/tools/search-icons.d.ts +12 -0
  36. package/dist/src/tools/search-icons.js +87 -0
  37. package/dist/src/tools/ungroup-nodes.js +8 -0
  38. package/dist/src/version.d.ts +1 -1
  39. package/dist/src/version.js +1 -1
  40. package/gui/dist/assets/index-B-q92Pfu.js +10 -0
  41. package/gui/dist/assets/index-PQqxUQLx.css +1 -0
  42. package/gui/dist/assets/search-C-KcHHKM.js +1 -0
  43. package/gui/dist/index.html +2 -2
  44. package/package.json +4 -2
  45. package/scripts/generate-icons.js +85 -0
  46. package/gui/dist/assets/index-C6fXmzfu.css +0 -1
  47. package/gui/dist/assets/index-Cmo-X8Zs.js +0 -10
@@ -4,8 +4,8 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>MCP Design</title>
7
- <script type="module" crossorigin src="./assets/index-Cmo-X8Zs.js"></script>
8
- <link rel="stylesheet" crossorigin href="./assets/index-C6fXmzfu.css">
7
+ <script type="module" crossorigin src="./assets/index-B-q92Pfu.js"></script>
8
+ <link rel="stylesheet" crossorigin href="./assets/index-PQqxUQLx.css">
9
9
  </head>
10
10
  <body>
11
11
  <div id="root"></div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@imenam/mcp-design",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "main": "dist/src/index.js",
5
5
  "directories": {
6
6
  "test": "test"
@@ -13,7 +13,8 @@
13
13
  "start": "node dist/src/index.js",
14
14
  "test": "node --test \"dist/test/*.test.js\"",
15
15
  "prepublishOnly": "npm run build",
16
- "release": "npm version patch && npm publish && git push --follow-tags"
16
+ "release": "npm version patch && npm publish && git push --follow-tags",
17
+ "generate-icons": "node scripts/generate-icons.js"
17
18
  },
18
19
  "keywords": [
19
20
  "mcp",
@@ -53,6 +54,7 @@
53
54
  },
54
55
  "devDependencies": {
55
56
  "@types/node": "^26.3.0",
57
+ "lucide-static": "^1.38.0",
56
58
  "typescript": "^7.0.2"
57
59
  }
58
60
  }
@@ -0,0 +1,85 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Fige la bibliotheque d'icones dans `shared/icons/` a partir de `lucide-static`.
4
+ *
5
+ * Les fichiers produits sont commites : ni le serveur MCP publie, ni le bundle
6
+ * de la GUI ne dependent de lucide a l'execution, et la geometrie d'un design
7
+ * ne peut pas changer sous les pieds de l'utilisateur au gre d'un `npm install`.
8
+ * Relancer `npm run generate-icons` apres une mise a jour de lucide-static.
9
+ */
10
+ import fs from 'fs';
11
+ import path from 'path';
12
+ import { createRequire } from 'module';
13
+ import { fileURLToPath } from 'url';
14
+
15
+ const require = createRequire(import.meta.url);
16
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
17
+ const rootDir = path.join(__dirname, '..');
18
+ const outDir = path.join(rootDir, 'shared', 'icons');
19
+
20
+ const iconNodes = require('lucide-static/icon-nodes.json');
21
+ const tags = require('lucide-static/tags.json');
22
+ const { version } = require('lucide-static/package.json');
23
+
24
+ /** Attributs de presentation portes par le noeud du design, jamais par l'icone elle-meme. */
25
+ const DROPPED_ATTRS = new Set(['stroke', 'stroke-width', 'stroke-linecap', 'stroke-linejoin', 'class', 'key']);
26
+
27
+ const names = Object.keys(iconNodes).sort();
28
+
29
+ const geometry = {};
30
+ for (const name of names) {
31
+ geometry[name] = iconNodes[name].map(([tag, attrs]) => {
32
+ const kept = {};
33
+ for (const [attr, value] of Object.entries(attrs ?? {})) {
34
+ if (!DROPPED_ATTRS.has(attr)) kept[attr] = String(value);
35
+ }
36
+ return [tag, kept];
37
+ });
38
+ }
39
+
40
+ /** Mots-cles de recherche : le nom eclate en segments, plus les synonymes de lucide. */
41
+ const keywords = {};
42
+ for (const name of names) {
43
+ const fromName = name.split('-');
44
+ const merged = [...new Set([...fromName, ...(tags[name] ?? [])])].filter((word) => word.length > 1);
45
+ if (merged.length > 0) keywords[name] = merged;
46
+ }
47
+
48
+ /**
49
+ * Les donnees sont embarquees comme une chaine JSON parsee au premier acces
50
+ * plutot que comme un litteral d'objet : un objet de 1800 entrees coute cher a
51
+ * analyser au demarrage, et le module est charge par le serveur stdio comme par
52
+ * le navigateur.
53
+ */
54
+ function moduleSource(header, exports) {
55
+ const body = exports
56
+ .map(([name, value]) => `export const ${name} = ${JSON.stringify(JSON.stringify(value))};`)
57
+ .join('\n\n');
58
+ return `${header}\n${body}\n`;
59
+ }
60
+
61
+ const banner = (what) =>
62
+ `// Auto-generated by scripts/generate-icons.js - do not edit manually.\n` +
63
+ `// ${what}\n` +
64
+ `// Source: lucide-static ${version}, ISC licence (https://lucide.dev).\n`;
65
+
66
+ fs.mkdirSync(outDir, { recursive: true });
67
+ fs.writeFileSync(
68
+ path.join(outDir, 'icon-data.ts'),
69
+ moduleSource(banner('Geometry of every icon, in the 24x24 grid.'), [
70
+ ['LUCIDE_VERSION', version],
71
+ ['ICON_DATA_JSON', geometry],
72
+ ]),
73
+ 'utf8'
74
+ );
75
+ fs.writeFileSync(
76
+ path.join(outDir, 'icon-keywords.ts'),
77
+ moduleSource(banner('Search keywords per icon. Loaded on demand, never by the renderer.'), [
78
+ ['ICON_KEYWORDS_JSON', keywords],
79
+ ]),
80
+ 'utf8'
81
+ );
82
+
83
+ console.log(`Generated ${names.length} icons from lucide-static ${version}`);
84
+ console.log(` ${path.join(outDir, 'icon-data.ts')}`);
85
+ console.log(` ${path.join(outDir, 'icon-keywords.ts')}`);
@@ -1 +0,0 @@
1
- :root{--ink:#16161a;--ink-soft:#5c5c66;--ink-faint:#8e8e99;--paper:#fff;--shell:#f4f4f2;--line:#e0e0dc;--line-strong:#c9c9c3;--accent:#1b4dd6;--accent-soft:#e8edfc;--danger:#b4231f;--ok:#1f7a45;color:var(--ink);-webkit-font-smoothing:antialiased;font-family:Inter,system-ui,-apple-system,Segoe UI,sans-serif;font-size:14px}*{box-sizing:border-box}body,html,#root{height:100%;margin:0}body{background:var(--shell)}button{font:inherit;color:inherit;cursor:pointer}input,select,textarea{font:inherit;color:inherit}h1,h2{letter-spacing:.02em;margin:0;font-size:13px;font-weight:600}code{background:var(--shell);border-radius:3px;padding:0 3px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px}.app{grid-template-columns:var(--left-panel,232px) 5px minmax(0, 1fr) 5px var(--right-panel,268px);height:100%;display:grid}.panel-resizer{background:var(--line);cursor:col-resize;touch-action:none;position:relative}.panel-resizer:after{content:"";position:absolute;inset:0 -3px}.panel-resizer:hover,.panel-resizer:active{background:var(--accent)}.sidebar,.right-rail{background:var(--paper);overflow-y:auto}.sidebar{border-right:1px solid var(--line);padding:14px}.right-rail{border-left:1px solid var(--line);flex-direction:column;display:flex}.workspace{flex-direction:column;min-width:0;display:flex}.workspace-empty{color:var(--ink-faint);flex:1;place-items:center;display:grid}.toolbar{background:var(--paper);border-bottom:1px solid var(--line);align-items:center;gap:16px;padding:8px 14px;display:flex}.tool-group{align-items:center;gap:4px;display:flex}.tool-button{background:0 0;border:1px solid #0000;border-radius:6px;align-items:center;gap:6px;padding:6px 10px;line-height:1;display:inline-flex}.tool-button:hover:not(:disabled){background:var(--shell)}.tool-button[data-active]{background:var(--accent-soft);border-color:var(--accent);color:var(--accent)}.tool-button:disabled{opacity:.35;cursor:default}.tool-glyph{text-align:center;flex-shrink:0;width:15px;font-size:15px}.tool-label{font-size:12px}.zoom-control{color:var(--ink-soft);align-items:center;gap:6px;font-size:12px;display:inline-flex}.zoom-control select{border:1px solid var(--line);background:var(--paper);border-radius:6px;padding:4px 6px}.toolbar-status{align-items:center;gap:8px;margin-left:auto;font-size:12px;display:flex}.status-name{font-weight:600}.status-chip{background:var(--shell);color:var(--ink-soft);border-radius:999px;padding:3px 8px}.status-chip[data-state=saved]{color:var(--ok)}.status-chip[data-state=error]{color:var(--danger)}.canvas-viewport{touch-action:none;overscroll-behavior:contain;flex:1;position:relative;overflow:hidden}.canvas-viewport[data-pan],.canvas-viewport[data-pan] .canvas-surface,.canvas-viewport[data-pan] .canvas-node{cursor:grab}.canvas-stage{transform-origin:0 0;position:absolute;top:0;left:0;box-shadow:0 1px 2px #00000014,0 12px 32px #00000014}.canvas-surface{transform-origin:0 0;position:absolute;top:0;left:0;overflow:hidden}.canvas-surface[data-tool=select]{cursor:default}.canvas-surface:not([data-tool=select]){cursor:crosshair}.canvas-svg{display:block}.canvas-node[data-hidden]{visibility:hidden}.canvas-group{pointer-events:none}.canvas-group .canvas-node{pointer-events:auto}.canvas-surface[data-tool=select] .canvas-node{cursor:move}.selection-frame{fill:none;stroke:var(--accent);stroke-width:1px;pointer-events:none}.creation-preview{fill:#1b4dd614;stroke:var(--accent);stroke-width:1px;stroke-dasharray:4 3;pointer-events:none}.marquee{fill:#1b4dd60f;stroke:var(--accent);stroke-width:1px;pointer-events:none}.handle{background:var(--paper);border:1px solid var(--accent);border-radius:2px;width:9px;height:9px;margin:-5px 0 0 -5px;position:absolute}.text-editor{border:1px solid var(--accent);resize:none;white-space:pre-wrap;background:#ffffffeb;outline:none;margin:0;padding:0;position:absolute;overflow:hidden}.design-tree{border-radius:6px;gap:2px;min-height:60px;display:grid}.design-tree[data-drop]{box-shadow:inset 0 0 0 1px var(--accent)}.design-group{gap:2px;display:grid}.design-group-header{width:100%;color:var(--ink-soft);text-align:left;background:0 0;border:1px solid #0000;border-radius:6px;align-items:center;gap:6px;padding:5px 6px;font-size:12px;font-weight:600;display:flex}.design-group-header:hover{background:var(--shell)}.design-group[data-drop]{background:var(--accent-soft);box-shadow:inset 0 0 0 1px var(--accent);border-radius:6px}.design-group[data-drop]>.design-group-header,.design-group[data-drop]>.design-group-header .design-group-caret,.design-group[data-drop]>.design-group-header .design-group-count{color:var(--accent)}.design-group-caret{width:10px;color:var(--ink-faint)}.design-group-name{text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;overflow:hidden}.design-group-count{color:var(--ink-faint);font-size:10px;font-weight:500}.sidebar-header{justify-content:space-between;align-items:center;margin-bottom:12px;display:flex}.ghost-button{border:1px solid var(--line-strong);background:0 0;border-radius:6px;padding:4px 8px;font-size:12px}.ghost-button:hover{background:var(--shell)}.primary-button{background:var(--accent);color:#fff;border:none;border-radius:6px;padding:6px 10px;font-size:12px}.primary-button:disabled{opacity:.4;cursor:default}.create-form{background:var(--shell);border-radius:8px;gap:6px;margin-bottom:12px;padding:10px;display:grid}.create-form input,.create-form select{border:1px solid var(--line);background:var(--paper);border-radius:6px;padding:6px 8px}.design-list{gap:2px;margin:0;padding:0;list-style:none;display:grid}.design-list li{align-items:center;gap:2px;display:flex}.design-item{text-align:left;background:0 0;border:1px solid #0000;border-radius:6px;flex:1;gap:2px;min-width:0;padding:8px;display:grid}.design-item:hover{background:var(--shell)}.design-item[data-active]{background:var(--accent-soft);border-color:var(--accent)}.design-name{text-overflow:ellipsis;white-space:nowrap;font-weight:500;overflow:hidden}.design-meta{color:var(--ink-faint);font-size:11px}.design-badge{color:#8a5a00;background:#fdf1d6;border-radius:999px;justify-self:start;padding:1px 6px;font-size:10px}.icon-button{color:var(--ink-faint);background:0 0;border:none;border-radius:4px;padding:4px 6px;line-height:1}.icon-button:hover:not(:disabled){background:var(--shell);color:var(--ink)}.icon-button:disabled{opacity:.3;cursor:default}.empty-hint{color:var(--ink-faint);margin:12px 0 0;font-size:12px;line-height:1.5}.inspector{border-bottom:1px solid var(--line);align-content:start;gap:10px;padding:14px;display:grid}.inspector h2{justify-content:space-between;align-items:baseline;gap:8px;display:flex;overflow:hidden}.inspector-type{color:var(--ink-faint);flex-shrink:0;font-size:11px;font-weight:400}.field{gap:4px;min-width:0;display:grid}.field>span{color:var(--ink-soft);font-size:11px}.field input,.field select,.field textarea{border:1px solid var(--line);background:var(--paper);border-radius:6px;width:100%;padding:5px 7px}.field textarea{resize:vertical;font-family:inherit}.field-row{grid-template-columns:1fr 1fr;gap:8px;display:grid}.color-input{align-items:center;gap:6px;display:flex}.color-input input[type=color]{flex-shrink:0;width:30px;height:28px;padding:2px}.toggle-button{border:1px solid var(--line);background:var(--paper);border-radius:6px;padding:5px 7px}.toggle-button[data-active]{background:var(--accent-soft);border-color:var(--accent);color:var(--accent)}.segmented{grid-template-columns:repeat(3,1fr);gap:4px;display:grid}.segmented button{border:1px solid var(--line);background:var(--paper);border-radius:6px;padding:5px 0}.segmented button[data-active]{background:var(--accent-soft);border-color:var(--accent);color:var(--accent)}.inspector-actions{grid-template-columns:1fr 1fr;gap:6px;margin-top:4px;display:grid}.inspector-actions button{border:1px solid var(--line-strong);background:var(--paper);border-radius:6px;padding:6px 4px;font-size:12px}.inspector-actions button:hover{background:var(--shell)}.inspector-actions .danger{color:var(--danger);border-color:#e8c4c3}.layers{flex-direction:column;min-height:0;padding:14px;display:flex}.layers-header{justify-content:space-between;align-items:center;margin-bottom:8px;display:flex}.layers-actions{gap:2px;display:flex}.layers ul{align-content:start;gap:1px;margin:0;padding:0;list-style:none;display:grid;overflow-y:auto}.layer-row{align-items:center;gap:2px;display:flex}.layer-twisty{width:14px;color:var(--ink-faint);text-align:center;background:0 0;border:none;flex-shrink:0;padding:0;font-size:10px;line-height:1}.layer-twisty:hover{color:var(--ink)}.layer-count{color:var(--ink-faint);background:var(--shell);border-radius:999px;flex-shrink:0;margin-left:auto;padding:0 5px;font-size:10px}.layer-item[data-group] .layer-name{font-weight:600}.layer-item{text-align:left;background:0 0;border:1px solid #0000;border-radius:5px;align-items:baseline;gap:8px;width:100%;min-width:0;padding:5px 7px;display:flex}.layer-item:hover{background:var(--shell)}.layer-item[data-active]{background:var(--accent-soft);border-color:var(--accent)}.layer-kind{color:var(--ink-faint);flex-shrink:0;width:58px;font-size:10px}.layer-name{text-overflow:ellipsis;white-space:nowrap;font-size:12px;overflow:hidden}.error-toast{background:var(--ink);color:#fff;border-radius:8px;align-items:center;gap:12px;padding:10px 14px;font-size:12px;display:flex;position:fixed;bottom:20px;left:50%;transform:translate(-50%);box-shadow:0 8px 24px #0003}.error-toast button{color:inherit;opacity:.7;background:0 0;border:none}