@wire-dsl/web 0.0.7 → 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 (127) hide show
  1. package/.turbo/turbo-build.log +103 -7
  2. package/CHANGELOG.md +30 -3
  3. package/dist/assets/abap-DLDM7-KI.js +1 -0
  4. package/dist/assets/apex-DNDY2TF8.js +1 -0
  5. package/dist/assets/azcli-Y6nb8tq_.js +1 -0
  6. package/dist/assets/bat-BwHxbl9M.js +1 -0
  7. package/dist/assets/bicep-CFznDFnq.js +2 -0
  8. package/dist/assets/cameligo-Bf6VGUru.js +1 -0
  9. package/dist/assets/clojure-Dnu-v4kV.js +1 -0
  10. package/dist/assets/codicon-ngg6Pgfi.ttf +0 -0
  11. package/dist/assets/coffee-Bd8akH9Z.js +1 -0
  12. package/dist/assets/cpp-BbWJElDN.js +1 -0
  13. package/dist/assets/csharp-Co3qMtFm.js +1 -0
  14. package/dist/assets/csp-D-4FJmMZ.js +1 -0
  15. package/dist/assets/css-DdJfP1eB.js +3 -0
  16. package/dist/assets/css.worker-DBVD8oXr.js +93 -0
  17. package/dist/assets/cssMode-BgkzAyoH.js +1 -0
  18. package/dist/assets/cypher-cTPe9QuQ.js +1 -0
  19. package/dist/assets/dart-BOtBlQCF.js +1 -0
  20. package/dist/assets/dockerfile-BG73LgW2.js +1 -0
  21. package/dist/assets/ecl-BEgZUVRK.js +1 -0
  22. package/dist/assets/elixir-BkW5O-1t.js +1 -0
  23. package/dist/assets/flow9-BeJ5waoc.js +1 -0
  24. package/dist/assets/freemarker2-D05KrEgD.js +3 -0
  25. package/dist/assets/fsharp-PahG7c26.js +1 -0
  26. package/dist/assets/go-acbASCJo.js +1 -0
  27. package/dist/assets/graphql-BxJiqAUM.js +1 -0
  28. package/dist/assets/handlebars-CmNF6dIr.js +1 -0
  29. package/dist/assets/hcl-DtV1sZF8.js +1 -0
  30. package/dist/assets/html-DdFfMtqo.js +1 -0
  31. package/dist/assets/html.worker-CwpTb9lJ.js +470 -0
  32. package/dist/assets/htmlMode-BzENSv3x.js +1 -0
  33. package/dist/assets/index-C6yQ9VSx.js +1595 -0
  34. package/dist/assets/index-CmAJnnOw.css +1 -0
  35. package/dist/assets/ini-Kd9XrMLS.js +1 -0
  36. package/dist/assets/java-CXBNlu9o.js +1 -0
  37. package/dist/assets/javascript-BDq34vkg.js +1 -0
  38. package/dist/assets/json.worker-BoL8UZqY.js +58 -0
  39. package/dist/assets/jsonMode-xsVJWt4Q.js +7 -0
  40. package/dist/assets/julia-cl7-CwDS.js +1 -0
  41. package/dist/assets/kotlin-s7OhZKlX.js +1 -0
  42. package/dist/assets/less-9HpZscsL.js +2 -0
  43. package/dist/assets/lexon-OrD6JF1K.js +1 -0
  44. package/dist/assets/liquid-BKLduW-j.js +1 -0
  45. package/dist/assets/lspLanguageFeatures-DENz5XIL.js +4 -0
  46. package/dist/assets/lua-Cyyb5UIc.js +1 -0
  47. package/dist/assets/m3-B8OfTtLu.js +1 -0
  48. package/dist/assets/markdown-BFxVWTOG.js +1 -0
  49. package/dist/assets/mdx-Cpg3g8iv.js +1 -0
  50. package/dist/assets/mips-CiqrrVzr.js +1 -0
  51. package/dist/assets/msdax-DmeGPVcC.js +1 -0
  52. package/dist/assets/mysql-C_tMU-Nz.js +1 -0
  53. package/dist/assets/objective-c-BDtDVThU.js +1 -0
  54. package/dist/assets/pascal-vHIfCaH5.js +1 -0
  55. package/dist/assets/pascaligo-DtZ0uQbO.js +1 -0
  56. package/dist/assets/perl-Ub6l9XKa.js +1 -0
  57. package/dist/assets/pgsql-BlNEE0v7.js +1 -0
  58. package/dist/assets/php-BBUBE1dy.js +1 -0
  59. package/dist/assets/pla-DSh2-awV.js +1 -0
  60. package/dist/assets/postiats-CocnycG-.js +1 -0
  61. package/dist/assets/powerquery-tScXyioY.js +1 -0
  62. package/dist/assets/powershell-COWaemsV.js +1 -0
  63. package/dist/assets/protobuf-Brw8urJB.js +2 -0
  64. package/dist/assets/pug-8SOpv6rk.js +1 -0
  65. package/dist/assets/python-Ca2JvAvf.js +1 -0
  66. package/dist/assets/qsharp-Bw9ernYp.js +1 -0
  67. package/dist/assets/r-j7ic8hl3.js +1 -0
  68. package/dist/assets/razor-B_xld0Yq.js +1 -0
  69. package/dist/assets/redis-Bu5POkcn.js +1 -0
  70. package/dist/assets/redshift-Bs9aos_-.js +1 -0
  71. package/dist/assets/restructuredtext-CqXO7rUv.js +1 -0
  72. package/dist/assets/ruby-zBfavPgS.js +1 -0
  73. package/dist/assets/rust-BzKRNQWT.js +1 -0
  74. package/dist/assets/sb-BBc9UKZt.js +1 -0
  75. package/dist/assets/scala-D9hQfWCl.js +1 -0
  76. package/dist/assets/scheme-BPhDTwHR.js +1 -0
  77. package/dist/assets/scss-CBJaRo0y.js +3 -0
  78. package/dist/assets/shell-DiJ1NA_G.js +1 -0
  79. package/dist/assets/solidity-Db0IVjzk.js +1 -0
  80. package/dist/assets/sophia-CnS9iZB_.js +1 -0
  81. package/dist/assets/sparql-CJmd_6j2.js +1 -0
  82. package/dist/assets/sql-ClhHkBeG.js +1 -0
  83. package/dist/assets/st-CHwy0fLd.js +1 -0
  84. package/dist/assets/swift-CnmFD0ga.js +1 -0
  85. package/dist/assets/systemverilog-Bs9z6M-B.js +1 -0
  86. package/dist/assets/tcl-Dm6ycUr_.js +1 -0
  87. package/dist/assets/ts.worker-BH9nVgjN.js +67718 -0
  88. package/dist/assets/tsMode-BinQkqy9.js +11 -0
  89. package/dist/assets/twig-Csy3S7wG.js +1 -0
  90. package/dist/assets/typescript-DQO38ZbJ.js +1 -0
  91. package/dist/assets/typespec-Btyra-wh.js +1 -0
  92. package/dist/assets/vb-Db0cS2oM.js +1 -0
  93. package/dist/assets/wgsl-BTesnYfV.js +298 -0
  94. package/dist/assets/xml-DF1bgZg2.js +1 -0
  95. package/dist/assets/yaml-BiNWh9S_.js +1 -0
  96. package/dist/examples/admin-dashboard.wire +95 -0
  97. package/dist/examples/analytics-dashboard.wire +65 -0
  98. package/dist/examples/form-example.wire +50 -0
  99. package/dist/examples/simple-dashboard.wire +40 -0
  100. package/dist/examples/simple-multi-screen.wire +30 -0
  101. package/dist/index.html +2 -2
  102. package/package.json +5 -3
  103. package/postcss.config.mjs +3 -1
  104. package/public/examples/admin-dashboard.wire +95 -0
  105. package/public/examples/analytics-dashboard.wire +65 -0
  106. package/public/examples/form-example.wire +50 -0
  107. package/public/examples/simple-dashboard.wire +40 -0
  108. package/public/examples/simple-multi-screen.wire +30 -0
  109. package/src/App.tsx +3 -13
  110. package/src/components/MonacoEditorComponent.tsx +112 -0
  111. package/src/components/WireLiveEditor.tsx +729 -0
  112. package/src/components/WireLiveHeader.tsx +469 -0
  113. package/src/components/index.ts +5 -0
  114. package/src/hooks/useCanvasZoom.ts +137 -0
  115. package/src/hooks/useFileSystemAccess.ts +123 -0
  116. package/src/hooks/useWireParser.ts +222 -0
  117. package/src/index.css +1 -3
  118. package/src/main.tsx +7 -5
  119. package/src/monaco/wireLanguage.ts +370 -0
  120. package/src/store/editorStore.ts +196 -0
  121. package/src/store/index.ts +2 -0
  122. package/tailwind.config.js +2 -1
  123. package/vite.config.ts +17 -0
  124. package/dist/assets/index-CHiOjnNN.js +0 -9
  125. package/dist/assets/index-CUIy2zPc.css +0 -1
  126. package/src/App.js +0 -4
  127. package/src/main.js +0 -6
@@ -0,0 +1,123 @@
1
+ import { useCallback, useState } from 'react';
2
+
3
+ declare global {
4
+ interface Window {
5
+ showOpenFilePicker?: (options?: any) => Promise<FileSystemFileHandle[]>;
6
+ showSaveFilePicker?: (options?: any) => Promise<FileSystemFileHandle>;
7
+ }
8
+ }
9
+
10
+ export interface FileSystemFileHandle {
11
+ name: string;
12
+ getFile(): Promise<File>;
13
+ createWritable(): Promise<FileSystemWritableFileStream>;
14
+ }
15
+
16
+ export interface FileSystemWritableFileStream {
17
+ write(data: string | ArrayBuffer | Blob): Promise<void>;
18
+ close(): Promise<void>;
19
+ }
20
+
21
+ export interface FileHandle {
22
+ name: string;
23
+ handle: FileSystemFileHandle;
24
+ }
25
+
26
+ interface UseFileSystemAccessReturn {
27
+ fileHandle: FileHandle | null;
28
+ setFileHandle: (handle: FileHandle | null) => void;
29
+ openFile: () => Promise<{ name: string; content: string; handle: FileSystemFileHandle } | null>;
30
+ saveFile: (content: string) => Promise<boolean>;
31
+ saveFileAs: (content: string, suggestedName?: string) => Promise<{ name: string; handle: FileSystemFileHandle } | false | null>;
32
+ }
33
+
34
+ export const useFileSystemAccess = (): UseFileSystemAccessReturn => {
35
+ const [fileHandle, setFileHandle] = useState<FileHandle | null>(null);
36
+
37
+ const openFile = useCallback(async (): Promise<{ name: string; content: string; handle: FileSystemFileHandle } | null> => {
38
+ try {
39
+ const handles = await (window.showOpenFilePicker as any)({
40
+ types: [
41
+ {
42
+ description: 'Wire Files',
43
+ accept: { 'text/plain': ['.wire'] },
44
+ },
45
+ ],
46
+ multiple: false,
47
+ });
48
+
49
+ if (handles.length === 0) return null;
50
+
51
+ const handle = handles[0];
52
+ const file = await handle.getFile();
53
+ const content = await file.text();
54
+
55
+ setFileHandle({ name: file.name, handle });
56
+ return { name: file.name, content, handle };
57
+ } catch (error) {
58
+ if (error instanceof DOMException && error.name !== 'AbortError') {
59
+ console.error('Error opening file:', error);
60
+ }
61
+ return null;
62
+ }
63
+ }, []);
64
+
65
+ const saveFile = useCallback(
66
+ async (content: string): Promise<boolean> => {
67
+ if (!fileHandle) return false;
68
+
69
+ try {
70
+ const writable = await fileHandle.handle.createWritable();
71
+ await writable.write(content);
72
+ await writable.close();
73
+ return true;
74
+ } catch (error) {
75
+ console.error('Error saving file:', error);
76
+ return false;
77
+ }
78
+ },
79
+ [fileHandle]
80
+ );
81
+
82
+ const saveFileAs = useCallback(
83
+ async (content: string, suggestedName?: string): Promise<{ name: string; handle: FileSystemFileHandle } | false | null> => {
84
+ try {
85
+ const handle = await (window.showSaveFilePicker as any)({
86
+ types: [
87
+ {
88
+ description: 'Wire Files',
89
+ accept: { 'text/plain': ['.wire'] },
90
+ },
91
+ ],
92
+ suggestedName: suggestedName || 'untitled.wire',
93
+ });
94
+
95
+ const writable = await handle.createWritable();
96
+ await writable.write(content);
97
+ await writable.close();
98
+
99
+ setFileHandle({ name: handle.name, handle });
100
+ return { name: handle.name, handle };
101
+ } catch (error) {
102
+ // Usuario canceló el diálogo
103
+ if (error instanceof DOMException && error.name === 'AbortError') {
104
+ return false;
105
+ }
106
+ // Error real
107
+ if (error instanceof DOMException && error.name !== 'AbortError') {
108
+ console.error('Error saving file:', error);
109
+ }
110
+ return null;
111
+ }
112
+ },
113
+ []
114
+ );
115
+
116
+ return {
117
+ fileHandle,
118
+ setFileHandle,
119
+ openFile,
120
+ saveFile,
121
+ saveFileAs,
122
+ };
123
+ };
@@ -0,0 +1,222 @@
1
+ import { useState, useEffect } from 'react';
2
+ import {
3
+ parseWireDSL,
4
+ generateIR,
5
+ calculateLayout,
6
+ renderToSVG,
7
+ } from '@wire-dsl/engine';
8
+ import type { IRContract } from '@wire-dsl/engine';
9
+
10
+ export interface WireRenderResult {
11
+ svg: string;
12
+ width: number;
13
+ height: number;
14
+ projectName: string;
15
+ screenCount: number;
16
+ componentCount: number;
17
+ screens: Array<{ name: string; id: string }>;
18
+ selectedScreenName: string;
19
+ }
20
+
21
+ export interface WireDiagnostic {
22
+ line: number;
23
+ column: number;
24
+ message: string;
25
+ severity: 'error' | 'warning';
26
+ }
27
+
28
+ /**
29
+ * Hook to parse Wire DSL code and render to SVG
30
+ *
31
+ * Uses @wire-dsl/engine for parsing, IR generation, layout calculation, and rendering.
32
+ * All operations run in the browser (engine is pure JS/TS with no Node.js dependencies).
33
+ *
34
+ * Pipeline:
35
+ * 1. Parse DSL code to AST using Chevrotain parser
36
+ * 2. Generate IR (Intermediate Representation) with validation
37
+ * 3. Calculate layout positions and dimensions
38
+ * 4. Render to SVG with all visual properties
39
+ */
40
+ export function useWireParser(code: string, selectedScreenName?: string | null) {
41
+ const [renderResult, setRenderResult] = useState<WireRenderResult | null>(null);
42
+ const [diagnostics, setDiagnostics] = useState<WireDiagnostic[]>([]);
43
+ const [renderState, setRenderState] = useState<'idle' | 'parsing' | 'rendering'>('idle');
44
+
45
+ useEffect(() => {
46
+ if (!code || code.trim().length === 0) {
47
+ setRenderResult(null);
48
+ setDiagnostics([]);
49
+ return;
50
+ }
51
+
52
+ const processWireCode = async () => {
53
+ try {
54
+ setRenderState('parsing');
55
+ const errors: WireDiagnostic[] = [];
56
+
57
+ // 1. Parse DSL to AST
58
+ let ast;
59
+ try {
60
+ ast = parseWireDSL(code);
61
+ } catch (parseError) {
62
+ const message =
63
+ parseError instanceof Error
64
+ ? parseError.message
65
+ : 'Failed to parse Wire DSL';
66
+ errors.push({
67
+ line: 1,
68
+ column: 1,
69
+ message,
70
+ severity: 'error',
71
+ });
72
+ setDiagnostics(errors);
73
+ setRenderResult(null);
74
+ setRenderState('idle');
75
+ return;
76
+ }
77
+
78
+ // 2. Generate IR
79
+ let ir: IRContract;
80
+ try {
81
+ ir = generateIR(ast);
82
+ } catch (irError) {
83
+ const message =
84
+ irError instanceof Error
85
+ ? irError.message
86
+ : 'Failed to generate IR';
87
+ errors.push({
88
+ line: 1,
89
+ column: 1,
90
+ message,
91
+ severity: 'error',
92
+ });
93
+ setDiagnostics(errors);
94
+ setRenderResult(null);
95
+ setRenderState('idle');
96
+ return;
97
+ }
98
+
99
+ // 3. Calculate layout
100
+ setRenderState('rendering');
101
+ let layout;
102
+ try {
103
+ layout = calculateLayout(ir);
104
+ } catch (layoutError) {
105
+ const message =
106
+ layoutError instanceof Error
107
+ ? layoutError.message
108
+ : 'Failed to calculate layout';
109
+ errors.push({
110
+ line: 1,
111
+ column: 1,
112
+ message,
113
+ severity: 'error',
114
+ });
115
+ setDiagnostics(errors);
116
+ setRenderResult(null);
117
+ setRenderState('idle');
118
+ return;
119
+ }
120
+
121
+ // 4. Render to SVG
122
+ let svgOutput: string;
123
+ const screenToRender = selectedScreenName
124
+ ? ir.project.screens.find((s) => s.name === selectedScreenName)
125
+ : null;
126
+
127
+ const screenName = screenToRender?.name || ir.project.screens[0]?.name;
128
+
129
+ try {
130
+ svgOutput = renderToSVG(ir, layout, { screenName });
131
+ } catch (renderError) {
132
+ const message =
133
+ renderError instanceof Error
134
+ ? renderError.message
135
+ : 'Failed to render SVG';
136
+ errors.push({
137
+ line: 1,
138
+ column: 1,
139
+ message,
140
+ severity: 'error',
141
+ });
142
+ setDiagnostics(errors);
143
+ setRenderResult(null);
144
+ setRenderState('idle');
145
+ return;
146
+ }
147
+
148
+ // Success: extract metadata and set result
149
+ const screenCount = ir.project.screens.length;
150
+ const componentCount = ir.project.screens.reduce(
151
+ (total: number, screen: any) => total + countComponents(screen),
152
+ 0
153
+ );
154
+
155
+ // Get dimensions for the rendered screen
156
+ const renderedScreen = ir.project.screens.find((s) => s.name === screenName);
157
+ const width = renderedScreen?.viewport.width || 800;
158
+ const height = renderedScreen?.viewport.height || 600;
159
+
160
+ // Build screens list with name and id
161
+ const screens = ir.project.screens.map((screen) => ({
162
+ name: screen.name,
163
+ id: screen.id,
164
+ }));
165
+
166
+ setRenderResult({
167
+ svg: svgOutput,
168
+ width,
169
+ height,
170
+ projectName: ir.project.name,
171
+ screenCount,
172
+ componentCount,
173
+ screens,
174
+ selectedScreenName: screenName,
175
+ });
176
+
177
+ setDiagnostics([]);
178
+ } catch (error) {
179
+ const message =
180
+ error instanceof Error ? error.message : 'Unknown error';
181
+ setDiagnostics([
182
+ {
183
+ line: 1,
184
+ column: 1,
185
+ message,
186
+ severity: 'error',
187
+ },
188
+ ]);
189
+ setRenderResult(null);
190
+ } finally {
191
+ setRenderState('idle');
192
+ }
193
+ };
194
+
195
+ processWireCode();
196
+ }, [code, selectedScreenName]);
197
+
198
+ return {
199
+ renderResult,
200
+ diagnostics,
201
+ renderState,
202
+ };
203
+ }
204
+
205
+ /**
206
+ * Helper to count components in a screen
207
+ */
208
+ function countComponents(screen: any): number {
209
+ if (!screen.layout) return 0;
210
+
211
+ let count = 0;
212
+ const countInNode = (node: any) => {
213
+ if (node.type === 'component') {
214
+ count++;
215
+ } else if (node.children) {
216
+ node.children.forEach(countInNode);
217
+ }
218
+ };
219
+
220
+ countInNode(screen.layout);
221
+ return count;
222
+ }
package/src/index.css CHANGED
@@ -1,6 +1,4 @@
1
- @tailwind base;
2
- @tailwind components;
3
- @tailwind utilities;
1
+ @import "tailwindcss";
4
2
 
5
3
  body {
6
4
  margin: 0;
package/src/main.tsx CHANGED
@@ -2,9 +2,11 @@ import React from 'react';
2
2
  import ReactDOM from 'react-dom/client';
3
3
  import App from './App';
4
4
  import './index.css';
5
+ import { registerWireLanguage } from './monaco/wireLanguage';
5
6
 
6
- ReactDOM.createRoot(document.getElementById('root')!).render(
7
- <React.StrictMode>
8
- <App />
9
- </React.StrictMode>
10
- );
7
+ // Registrar lenguaje Wire en Monaco
8
+ registerWireLanguage();
9
+
10
+ // Render app
11
+ const root = ReactDOM.createRoot(document.getElementById('root')!);
12
+ root.render(<App />);