@ryndesign/preview 0.1.1
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.
- package/LICENSE +21 -0
- package/client/index.html +12 -0
- package/client/src/App.tsx +261 -0
- package/client/src/components/CodeViewer.tsx +88 -0
- package/client/src/components/ComponentBrowser.tsx +54 -0
- package/client/src/components/PreviewPanel.tsx +188 -0
- package/client/src/components/ThemeSwitcher.tsx +27 -0
- package/client/src/components/TokenEditor.tsx +113 -0
- package/client/src/hooks/useTokens.ts +14 -0
- package/client/src/hooks/useWebSocket.ts +116 -0
- package/client/src/index.tsx +6 -0
- package/dist/index.cjs +691 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +8 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +660 -0
- package/dist/index.js.map +1 -0
- package/package.json +57 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,691 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __esm = (fn, res) => function __init() {
|
|
9
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
10
|
+
};
|
|
11
|
+
var __export = (target, all) => {
|
|
12
|
+
for (var name in all)
|
|
13
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
14
|
+
};
|
|
15
|
+
var __copyProps = (to, from, except, desc) => {
|
|
16
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
17
|
+
for (let key of __getOwnPropNames(from))
|
|
18
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
19
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
20
|
+
}
|
|
21
|
+
return to;
|
|
22
|
+
};
|
|
23
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
24
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
25
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
26
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
27
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
28
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
29
|
+
mod
|
|
30
|
+
));
|
|
31
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
32
|
+
|
|
33
|
+
// ../../node_modules/.pnpm/@rolldown+pluginutils@1.0.0-rc.7/node_modules/@rolldown/pluginutils/dist/utils.js
|
|
34
|
+
var init_utils = __esm({
|
|
35
|
+
"../../node_modules/.pnpm/@rolldown+pluginutils@1.0.0-rc.7/node_modules/@rolldown/pluginutils/dist/utils.js"() {
|
|
36
|
+
"use strict";
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// ../../node_modules/.pnpm/@rolldown+pluginutils@1.0.0-rc.7/node_modules/@rolldown/pluginutils/dist/filter/composable-filters.js
|
|
41
|
+
var init_composable_filters = __esm({
|
|
42
|
+
"../../node_modules/.pnpm/@rolldown+pluginutils@1.0.0-rc.7/node_modules/@rolldown/pluginutils/dist/filter/composable-filters.js"() {
|
|
43
|
+
"use strict";
|
|
44
|
+
init_utils();
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// ../../node_modules/.pnpm/@rolldown+pluginutils@1.0.0-rc.7/node_modules/@rolldown/pluginutils/dist/filter/filter-vite-plugins.js
|
|
49
|
+
var init_filter_vite_plugins = __esm({
|
|
50
|
+
"../../node_modules/.pnpm/@rolldown+pluginutils@1.0.0-rc.7/node_modules/@rolldown/pluginutils/dist/filter/filter-vite-plugins.js"() {
|
|
51
|
+
"use strict";
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// ../../node_modules/.pnpm/@rolldown+pluginutils@1.0.0-rc.7/node_modules/@rolldown/pluginutils/dist/filter/simple-filters.js
|
|
56
|
+
function exactRegex(str, flags) {
|
|
57
|
+
return new RegExp(`^${escapeRegex(str)}$`, flags);
|
|
58
|
+
}
|
|
59
|
+
function escapeRegex(str) {
|
|
60
|
+
return str.replace(escapeRegexRE, "\\$&");
|
|
61
|
+
}
|
|
62
|
+
function makeIdFiltersToMatchWithQuery(input) {
|
|
63
|
+
if (!Array.isArray(input)) {
|
|
64
|
+
return makeIdFilterToMatchWithQuery(
|
|
65
|
+
// Array.isArray cannot narrow the type
|
|
66
|
+
// https://github.com/microsoft/TypeScript/issues/17002
|
|
67
|
+
input
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
return input.map((i) => makeIdFilterToMatchWithQuery(i));
|
|
71
|
+
}
|
|
72
|
+
function makeIdFilterToMatchWithQuery(input) {
|
|
73
|
+
if (typeof input === "string") {
|
|
74
|
+
return `${input}{?*,}`;
|
|
75
|
+
}
|
|
76
|
+
return makeRegexIdFilterToMatchWithQuery(input);
|
|
77
|
+
}
|
|
78
|
+
function makeRegexIdFilterToMatchWithQuery(input) {
|
|
79
|
+
return new RegExp(
|
|
80
|
+
// replace `$` with `(?:\?.*)?$` (ignore `\$`)
|
|
81
|
+
input.source.replace(/(?<!\\)\$/g, "(?:\\?.*)?$"),
|
|
82
|
+
input.flags
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
var escapeRegexRE;
|
|
86
|
+
var init_simple_filters = __esm({
|
|
87
|
+
"../../node_modules/.pnpm/@rolldown+pluginutils@1.0.0-rc.7/node_modules/@rolldown/pluginutils/dist/filter/simple-filters.js"() {
|
|
88
|
+
"use strict";
|
|
89
|
+
escapeRegexRE = /[-/\\^$*+?.()|[\]{}]/g;
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// ../../node_modules/.pnpm/@rolldown+pluginutils@1.0.0-rc.7/node_modules/@rolldown/pluginutils/dist/filter/index.js
|
|
94
|
+
var init_filter = __esm({
|
|
95
|
+
"../../node_modules/.pnpm/@rolldown+pluginutils@1.0.0-rc.7/node_modules/@rolldown/pluginutils/dist/filter/index.js"() {
|
|
96
|
+
"use strict";
|
|
97
|
+
init_composable_filters();
|
|
98
|
+
init_filter_vite_plugins();
|
|
99
|
+
init_simple_filters();
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
// ../../node_modules/.pnpm/@rolldown+pluginutils@1.0.0-rc.7/node_modules/@rolldown/pluginutils/dist/index.js
|
|
104
|
+
var init_dist = __esm({
|
|
105
|
+
"../../node_modules/.pnpm/@rolldown+pluginutils@1.0.0-rc.7/node_modules/@rolldown/pluginutils/dist/index.js"() {
|
|
106
|
+
"use strict";
|
|
107
|
+
init_filter();
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// ../../node_modules/.pnpm/@vitejs+plugin-react@6.0.1_vite@6.4.1_@types+node@25.5.0_jiti@2.6.1_/node_modules/@vitejs/plugin-react/dist/index.js
|
|
112
|
+
var dist_exports = {};
|
|
113
|
+
__export(dist_exports, {
|
|
114
|
+
default: () => viteReact,
|
|
115
|
+
"module.exports": () => viteReactForCjs,
|
|
116
|
+
reactCompilerPreset: () => reactCompilerPreset
|
|
117
|
+
});
|
|
118
|
+
function virtualPreamblePlugin({ name, isEnabled }) {
|
|
119
|
+
return {
|
|
120
|
+
name: "vite:react-virtual-preamble",
|
|
121
|
+
resolveId: {
|
|
122
|
+
order: "pre",
|
|
123
|
+
filter: { id: exactRegex(name) },
|
|
124
|
+
handler(source) {
|
|
125
|
+
if (source === name) return "\0" + source;
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
load: {
|
|
129
|
+
filter: { id: exactRegex("\0" + name) },
|
|
130
|
+
handler(id) {
|
|
131
|
+
if (id === "\0" + name) {
|
|
132
|
+
if (isEnabled()) return preambleCode.replace("__BASE__", "/");
|
|
133
|
+
return "";
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
function viteReact(opts = {}) {
|
|
140
|
+
const include = opts.include ?? defaultIncludeRE;
|
|
141
|
+
const exclude = opts.exclude ?? defaultExcludeRE;
|
|
142
|
+
const jsxImportSource = opts.jsxImportSource ?? "react";
|
|
143
|
+
const jsxImportRuntime = `${jsxImportSource}/jsx-runtime`;
|
|
144
|
+
const jsxImportDevRuntime = `${jsxImportSource}/jsx-dev-runtime`;
|
|
145
|
+
let runningInVite = false;
|
|
146
|
+
let isProduction = true;
|
|
147
|
+
let skipFastRefresh = true;
|
|
148
|
+
let base;
|
|
149
|
+
let isBundledDev = false;
|
|
150
|
+
const viteBabel = {
|
|
151
|
+
name: "vite:react-babel",
|
|
152
|
+
enforce: "pre",
|
|
153
|
+
config(_userConfig, { command }) {
|
|
154
|
+
if (opts.jsxRuntime === "classic") return { oxc: {
|
|
155
|
+
jsx: {
|
|
156
|
+
runtime: "classic",
|
|
157
|
+
refresh: command === "serve"
|
|
158
|
+
},
|
|
159
|
+
jsxRefreshInclude: makeIdFiltersToMatchWithQuery(include),
|
|
160
|
+
jsxRefreshExclude: makeIdFiltersToMatchWithQuery(exclude)
|
|
161
|
+
} };
|
|
162
|
+
else return {
|
|
163
|
+
oxc: {
|
|
164
|
+
jsx: {
|
|
165
|
+
runtime: "automatic",
|
|
166
|
+
importSource: opts.jsxImportSource,
|
|
167
|
+
refresh: command === "serve"
|
|
168
|
+
},
|
|
169
|
+
jsxRefreshInclude: makeIdFiltersToMatchWithQuery(include),
|
|
170
|
+
jsxRefreshExclude: makeIdFiltersToMatchWithQuery(exclude)
|
|
171
|
+
},
|
|
172
|
+
optimizeDeps: { rolldownOptions: { transform: { jsx: { runtime: "automatic" } } } }
|
|
173
|
+
};
|
|
174
|
+
},
|
|
175
|
+
configResolved(config) {
|
|
176
|
+
runningInVite = true;
|
|
177
|
+
base = config.base;
|
|
178
|
+
if (config.experimental.bundledDev) isBundledDev = true;
|
|
179
|
+
isProduction = config.isProduction;
|
|
180
|
+
skipFastRefresh = isProduction || config.command === "build" || config.server.hmr === false;
|
|
181
|
+
},
|
|
182
|
+
options(options) {
|
|
183
|
+
if (!runningInVite) {
|
|
184
|
+
options.transform ??= {};
|
|
185
|
+
options.transform.jsx = {
|
|
186
|
+
runtime: opts.jsxRuntime,
|
|
187
|
+
importSource: opts.jsxImportSource
|
|
188
|
+
};
|
|
189
|
+
return options;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
const viteRefreshWrapper = {
|
|
194
|
+
name: "vite:react:refresh-wrapper",
|
|
195
|
+
apply: "serve",
|
|
196
|
+
async applyToEnvironment(env) {
|
|
197
|
+
if (env.config.consumer !== "client" || skipFastRefresh) return false;
|
|
198
|
+
return (0, import_internal.reactRefreshWrapperPlugin)({
|
|
199
|
+
cwd: process.cwd(),
|
|
200
|
+
include: makeIdFiltersToMatchWithQuery(include),
|
|
201
|
+
exclude: makeIdFiltersToMatchWithQuery(exclude),
|
|
202
|
+
jsxImportSource,
|
|
203
|
+
reactRefreshHost: opts.reactRefreshHost ?? ""
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
const viteConfigPost = {
|
|
208
|
+
name: "vite:react:config-post",
|
|
209
|
+
enforce: "post",
|
|
210
|
+
config(userConfig) {
|
|
211
|
+
if (userConfig.server?.hmr === false) return { oxc: { jsx: { refresh: false } } };
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
const viteReactRefreshBundledDevMode = {
|
|
215
|
+
name: "vite:react-refresh-fbm",
|
|
216
|
+
enforce: "pre",
|
|
217
|
+
transformIndexHtml: {
|
|
218
|
+
handler() {
|
|
219
|
+
if (!skipFastRefresh && isBundledDev) return [{
|
|
220
|
+
tag: "script",
|
|
221
|
+
attrs: { type: "module" },
|
|
222
|
+
children: getPreambleCode(base)
|
|
223
|
+
}];
|
|
224
|
+
},
|
|
225
|
+
order: "pre"
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
const dependencies = [
|
|
229
|
+
"react",
|
|
230
|
+
"react-dom",
|
|
231
|
+
jsxImportDevRuntime,
|
|
232
|
+
jsxImportRuntime
|
|
233
|
+
];
|
|
234
|
+
return [
|
|
235
|
+
viteBabel,
|
|
236
|
+
viteRefreshWrapper,
|
|
237
|
+
viteConfigPost,
|
|
238
|
+
viteReactRefreshBundledDevMode,
|
|
239
|
+
{
|
|
240
|
+
name: "vite:react-refresh",
|
|
241
|
+
enforce: "pre",
|
|
242
|
+
config: (userConfig) => ({
|
|
243
|
+
build: silenceUseClientWarning(userConfig),
|
|
244
|
+
optimizeDeps: { include: dependencies }
|
|
245
|
+
}),
|
|
246
|
+
resolveId: {
|
|
247
|
+
filter: { id: exactRegex(runtimePublicPath) },
|
|
248
|
+
handler(id) {
|
|
249
|
+
if (id === "/@react-refresh") return id;
|
|
250
|
+
}
|
|
251
|
+
},
|
|
252
|
+
load: {
|
|
253
|
+
filter: { id: exactRegex(runtimePublicPath) },
|
|
254
|
+
handler(id) {
|
|
255
|
+
if (id === "/@react-refresh") return (0, import_node_fs.readFileSync)(refreshRuntimePath, "utf-8").replace(/__README_URL__/g, "https://github.com/vitejs/vite-plugin-react/tree/main/packages/plugin-react");
|
|
256
|
+
}
|
|
257
|
+
},
|
|
258
|
+
transformIndexHtml() {
|
|
259
|
+
if (!skipFastRefresh && !isBundledDev) return [{
|
|
260
|
+
tag: "script",
|
|
261
|
+
attrs: { type: "module" },
|
|
262
|
+
children: getPreambleCode(base)
|
|
263
|
+
}];
|
|
264
|
+
}
|
|
265
|
+
},
|
|
266
|
+
virtualPreamblePlugin({
|
|
267
|
+
name: "@vitejs/plugin-react/preamble",
|
|
268
|
+
isEnabled: () => !skipFastRefresh && !isBundledDev
|
|
269
|
+
})
|
|
270
|
+
];
|
|
271
|
+
}
|
|
272
|
+
function viteReactForCjs(options) {
|
|
273
|
+
return viteReact.call(this, options);
|
|
274
|
+
}
|
|
275
|
+
var import_node_fs, import_node_path2, import_node_url, import_internal, import_meta, runtimePublicPath, preambleCode, getPreambleCode, silenceUseClientWarning, reactCompilerPreset, refreshRuntimePath, defaultIncludeRE, defaultExcludeRE;
|
|
276
|
+
var init_dist2 = __esm({
|
|
277
|
+
"../../node_modules/.pnpm/@vitejs+plugin-react@6.0.1_vite@6.4.1_@types+node@25.5.0_jiti@2.6.1_/node_modules/@vitejs/plugin-react/dist/index.js"() {
|
|
278
|
+
"use strict";
|
|
279
|
+
import_node_fs = require("fs");
|
|
280
|
+
import_node_path2 = require("path");
|
|
281
|
+
import_node_url = require("url");
|
|
282
|
+
init_dist();
|
|
283
|
+
import_internal = require("vite/internal");
|
|
284
|
+
import_meta = {};
|
|
285
|
+
runtimePublicPath = "/@react-refresh";
|
|
286
|
+
preambleCode = `import { injectIntoGlobalHook } from "__BASE__${runtimePublicPath.slice(1)}";
|
|
287
|
+
injectIntoGlobalHook(window);
|
|
288
|
+
window.$RefreshReg$ = () => {};
|
|
289
|
+
window.$RefreshSig$ = () => (type) => type;`;
|
|
290
|
+
getPreambleCode = (base) => preambleCode.replace("__BASE__", base);
|
|
291
|
+
silenceUseClientWarning = (userConfig) => ({ rollupOptions: { onwarn(warning, defaultHandler) {
|
|
292
|
+
if (warning.code === "MODULE_LEVEL_DIRECTIVE" && (warning.message.includes("use client") || warning.message.includes("use server"))) return;
|
|
293
|
+
if (warning.code === "SOURCEMAP_ERROR" && warning.message.includes("resolve original location") && warning.pos === 0) return;
|
|
294
|
+
if (userConfig.build?.rollupOptions?.onwarn) userConfig.build.rollupOptions.onwarn(warning, defaultHandler);
|
|
295
|
+
else defaultHandler(warning);
|
|
296
|
+
} } });
|
|
297
|
+
reactCompilerPreset = (options = {}) => ({
|
|
298
|
+
preset: () => ({ plugins: [["babel-plugin-react-compiler", options]] }),
|
|
299
|
+
rolldown: {
|
|
300
|
+
filter: { code: options.compilationMode === "annotation" ? /['"]use memo['"]/ : /\b[A-Z]|\buse/ },
|
|
301
|
+
applyToEnvironmentHook: (env) => env.config.consumer === "client",
|
|
302
|
+
optimizeDeps: { include: options.target === "17" || options.target === "18" ? ["react-compiler-runtime"] : ["react/compiler-runtime"] }
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
refreshRuntimePath = (0, import_node_path2.join)((0, import_node_path2.dirname)((0, import_node_url.fileURLToPath)(import_meta.url)), "refresh-runtime.js");
|
|
306
|
+
defaultIncludeRE = /\.[tj]sx?$/;
|
|
307
|
+
defaultExcludeRE = /\/node_modules\//;
|
|
308
|
+
viteReact.preambleCode = preambleCode;
|
|
309
|
+
Object.assign(viteReactForCjs, {
|
|
310
|
+
default: viteReactForCjs,
|
|
311
|
+
reactCompilerPreset
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
// src/index.ts
|
|
317
|
+
var index_exports = {};
|
|
318
|
+
__export(index_exports, {
|
|
319
|
+
startPreviewServer: () => startPreviewServer
|
|
320
|
+
});
|
|
321
|
+
module.exports = __toCommonJS(index_exports);
|
|
322
|
+
|
|
323
|
+
// src/server/index.ts
|
|
324
|
+
var import_vite = require("vite");
|
|
325
|
+
var import_ws = require("ws");
|
|
326
|
+
var import_node_http = __toESM(require("http"), 1);
|
|
327
|
+
var import_node_path3 = __toESM(require("path"), 1);
|
|
328
|
+
|
|
329
|
+
// src/server/api-routes.ts
|
|
330
|
+
function setupApiRoutes(builder) {
|
|
331
|
+
return (req, res) => {
|
|
332
|
+
const url = new URL(req.url ?? "/", `http://${req.headers.host}`);
|
|
333
|
+
const pathname = url.pathname;
|
|
334
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
335
|
+
res.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, OPTIONS");
|
|
336
|
+
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
|
|
337
|
+
if (req.method === "OPTIONS") {
|
|
338
|
+
res.writeHead(204);
|
|
339
|
+
res.end();
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
try {
|
|
343
|
+
if (pathname === "/api/tokens" && req.method === "GET") {
|
|
344
|
+
json(res, builder.getTokenSet());
|
|
345
|
+
} else if (pathname === "/api/themes" && req.method === "GET") {
|
|
346
|
+
json(res, builder.getThemes());
|
|
347
|
+
} else if (pathname === "/api/components" && req.method === "GET") {
|
|
348
|
+
json(res, builder.getComponents());
|
|
349
|
+
} else if (pathname === "/api/snippets" && req.method === "GET") {
|
|
350
|
+
const platform = url.searchParams.get("platform") ?? "react";
|
|
351
|
+
const component = url.searchParams.get("component") ?? void 0;
|
|
352
|
+
const type = url.searchParams.get("type") ?? void 0;
|
|
353
|
+
builder.generateSnippets(platform, component, type).then((code) => {
|
|
354
|
+
json(res, { code });
|
|
355
|
+
}).catch((err) => {
|
|
356
|
+
res.writeHead(500);
|
|
357
|
+
json(res, { error: err.message });
|
|
358
|
+
});
|
|
359
|
+
return;
|
|
360
|
+
} else if (pathname === "/api/tokens" && req.method === "PUT") {
|
|
361
|
+
let body = "";
|
|
362
|
+
req.on("data", (chunk) => {
|
|
363
|
+
body += chunk;
|
|
364
|
+
});
|
|
365
|
+
req.on("end", async () => {
|
|
366
|
+
const { path: path3, value, theme } = JSON.parse(body);
|
|
367
|
+
await builder.updateToken(path3, value, theme);
|
|
368
|
+
json(res, { success: true });
|
|
369
|
+
});
|
|
370
|
+
} else if (pathname === "/api/generated" && req.method === "GET") {
|
|
371
|
+
const platform = url.searchParams.get("platform");
|
|
372
|
+
json(res, builder.getGeneratedFiles(platform ?? void 0));
|
|
373
|
+
} else {
|
|
374
|
+
res.writeHead(404);
|
|
375
|
+
json(res, { error: "Not found" });
|
|
376
|
+
}
|
|
377
|
+
} catch (err) {
|
|
378
|
+
res.writeHead(500);
|
|
379
|
+
json(res, { error: err.message });
|
|
380
|
+
}
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
function json(res, data) {
|
|
384
|
+
if (!res.headersSent) {
|
|
385
|
+
res.setHeader("Content-Type", "application/json");
|
|
386
|
+
}
|
|
387
|
+
res.end(JSON.stringify(data));
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// src/server/ws-handler.ts
|
|
391
|
+
function setupWsHandler(wss, builder) {
|
|
392
|
+
wss.on("connection", (ws) => {
|
|
393
|
+
console.log("Preview client connected");
|
|
394
|
+
ws.send(JSON.stringify({
|
|
395
|
+
type: "init",
|
|
396
|
+
tokenSet: builder.getTokenSet(),
|
|
397
|
+
themes: builder.getThemes(),
|
|
398
|
+
components: builder.getComponents()
|
|
399
|
+
}));
|
|
400
|
+
ws.on("message", async (data) => {
|
|
401
|
+
try {
|
|
402
|
+
const message = JSON.parse(data.toString());
|
|
403
|
+
switch (message.type) {
|
|
404
|
+
case "token-update": {
|
|
405
|
+
const update = message;
|
|
406
|
+
await builder.updateToken(update.path, update.value, update.theme);
|
|
407
|
+
broadcast(wss, {
|
|
408
|
+
type: "rebuild-complete",
|
|
409
|
+
changedTokens: [update.path],
|
|
410
|
+
timestamp: Date.now()
|
|
411
|
+
});
|
|
412
|
+
break;
|
|
413
|
+
}
|
|
414
|
+
case "theme-change": {
|
|
415
|
+
const themeMsg = message;
|
|
416
|
+
broadcast(wss, {
|
|
417
|
+
type: "theme-switched",
|
|
418
|
+
theme: themeMsg.theme,
|
|
419
|
+
tokens: builder.getThemeTokens(themeMsg.theme)
|
|
420
|
+
});
|
|
421
|
+
break;
|
|
422
|
+
}
|
|
423
|
+
case "request-state": {
|
|
424
|
+
ws.send(JSON.stringify({
|
|
425
|
+
type: "full-state",
|
|
426
|
+
tokenSet: builder.getTokenSet(),
|
|
427
|
+
themes: builder.getThemes(),
|
|
428
|
+
components: builder.getComponents()
|
|
429
|
+
}));
|
|
430
|
+
break;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
} catch (err) {
|
|
434
|
+
ws.send(JSON.stringify({
|
|
435
|
+
type: "error",
|
|
436
|
+
message: err.message
|
|
437
|
+
}));
|
|
438
|
+
}
|
|
439
|
+
});
|
|
440
|
+
ws.on("close", () => {
|
|
441
|
+
console.log("Preview client disconnected");
|
|
442
|
+
});
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
function broadcast(wss, message) {
|
|
446
|
+
const data = JSON.stringify(message);
|
|
447
|
+
for (const client of wss.clients) {
|
|
448
|
+
if (client.readyState === 1) {
|
|
449
|
+
client.send(data);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// src/server/watcher.ts
|
|
455
|
+
var import_chokidar = require("chokidar");
|
|
456
|
+
function setupWatcher(builder, wss, cwd) {
|
|
457
|
+
const watcher = (0, import_chokidar.watch)(
|
|
458
|
+
["tokens/**/*.tokens.json", "components/**/*.component.json"],
|
|
459
|
+
{
|
|
460
|
+
cwd,
|
|
461
|
+
ignoreInitial: true,
|
|
462
|
+
awaitWriteFinish: {
|
|
463
|
+
stabilityThreshold: 300,
|
|
464
|
+
pollInterval: 50
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
);
|
|
468
|
+
let debounceTimer = null;
|
|
469
|
+
const handleChange = (changedPath) => {
|
|
470
|
+
if (debounceTimer) clearTimeout(debounceTimer);
|
|
471
|
+
debounceTimer = setTimeout(async () => {
|
|
472
|
+
console.log(`File changed: ${changedPath}`);
|
|
473
|
+
try {
|
|
474
|
+
await builder.rebuild();
|
|
475
|
+
const data = JSON.stringify({
|
|
476
|
+
type: "rebuild-complete",
|
|
477
|
+
changedTokens: [],
|
|
478
|
+
timestamp: Date.now(),
|
|
479
|
+
tokenSet: builder.getTokenSet(),
|
|
480
|
+
components: builder.getComponents()
|
|
481
|
+
});
|
|
482
|
+
for (const client of wss.clients) {
|
|
483
|
+
if (client.readyState === 1) {
|
|
484
|
+
client.send(data);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
} catch (err) {
|
|
488
|
+
console.error("Rebuild failed:", err.message);
|
|
489
|
+
}
|
|
490
|
+
}, 300);
|
|
491
|
+
};
|
|
492
|
+
watcher.on("change", handleChange);
|
|
493
|
+
watcher.on("add", handleChange);
|
|
494
|
+
watcher.on("unlink", handleChange);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// src/server/incremental-build.ts
|
|
498
|
+
var import_core = require("@ryndesign/core");
|
|
499
|
+
var import_promises = __toESM(require("fs/promises"), 1);
|
|
500
|
+
var import_node_path = __toESM(require("path"), 1);
|
|
501
|
+
var IncrementalBuilder = class {
|
|
502
|
+
tokenSet = null;
|
|
503
|
+
components = [];
|
|
504
|
+
generatedFiles = /* @__PURE__ */ new Map();
|
|
505
|
+
generators = [];
|
|
506
|
+
cwd;
|
|
507
|
+
configPath;
|
|
508
|
+
constructor(cwd, configPath) {
|
|
509
|
+
this.cwd = cwd;
|
|
510
|
+
this.configPath = configPath;
|
|
511
|
+
}
|
|
512
|
+
async initialBuild() {
|
|
513
|
+
await this.rebuild();
|
|
514
|
+
}
|
|
515
|
+
async rebuild() {
|
|
516
|
+
const configFile = this.configPath ?? "ryndesign.config.ts";
|
|
517
|
+
const tokens = ["tokens/**/*.tokens.json"];
|
|
518
|
+
const componentPatterns = ["components/**/*.component.json"];
|
|
519
|
+
let themes = void 0;
|
|
520
|
+
try {
|
|
521
|
+
const configPath = import_node_path.default.resolve(this.cwd, configFile);
|
|
522
|
+
const content = await import_promises.default.readFile(configPath, "utf-8");
|
|
523
|
+
if (content.includes("dark")) {
|
|
524
|
+
themes = {
|
|
525
|
+
default: "light",
|
|
526
|
+
dark: { file: import_node_path.default.resolve(this.cwd, "tokens/dark.tokens.json") }
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
} catch {
|
|
530
|
+
}
|
|
531
|
+
this.tokenSet = await (0, import_core.buildTokenSet)({
|
|
532
|
+
tokens,
|
|
533
|
+
basePath: this.cwd,
|
|
534
|
+
themes
|
|
535
|
+
});
|
|
536
|
+
try {
|
|
537
|
+
const componentDefs = await (0, import_core.loadComponents)(componentPatterns, this.cwd);
|
|
538
|
+
this.components = componentDefs.map((def) => (0, import_core.resolveComponent)(def, this.tokenSet));
|
|
539
|
+
} catch {
|
|
540
|
+
this.components = [];
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
getTokenSet() {
|
|
544
|
+
return this.tokenSet;
|
|
545
|
+
}
|
|
546
|
+
getThemes() {
|
|
547
|
+
if (!this.tokenSet) return {};
|
|
548
|
+
return {
|
|
549
|
+
default: this.tokenSet.themes.default,
|
|
550
|
+
available: Object.keys(this.tokenSet.themes.themes),
|
|
551
|
+
themes: this.tokenSet.themes.themes
|
|
552
|
+
};
|
|
553
|
+
}
|
|
554
|
+
getThemeTokens(theme) {
|
|
555
|
+
if (!this.tokenSet) return {};
|
|
556
|
+
const themeData = this.tokenSet.themes.themes[theme];
|
|
557
|
+
if (!themeData) return {};
|
|
558
|
+
return {
|
|
559
|
+
name: themeData.name,
|
|
560
|
+
tokens: themeData.tokens
|
|
561
|
+
};
|
|
562
|
+
}
|
|
563
|
+
getComponents() {
|
|
564
|
+
return this.components;
|
|
565
|
+
}
|
|
566
|
+
setGenerators(generators) {
|
|
567
|
+
this.generators = generators;
|
|
568
|
+
}
|
|
569
|
+
async generateSnippets(platform, componentName, type) {
|
|
570
|
+
if (!this.tokenSet) return "";
|
|
571
|
+
const generator = this.generators.find((g) => g.name === platform);
|
|
572
|
+
if (!generator) return `// Generator for "${platform}" not available`;
|
|
573
|
+
const { createGeneratorHelpers } = await import("@ryndesign/core");
|
|
574
|
+
const ctx = {
|
|
575
|
+
tokenSet: this.tokenSet,
|
|
576
|
+
config: { outDir: "generated" },
|
|
577
|
+
outputDir: import_node_path.default.resolve(this.cwd, "generated"),
|
|
578
|
+
helpers: createGeneratorHelpers(),
|
|
579
|
+
components: this.components
|
|
580
|
+
};
|
|
581
|
+
try {
|
|
582
|
+
if (type === "tokens") {
|
|
583
|
+
const files = await generator.generateTokens(ctx);
|
|
584
|
+
return files.map((f) => `// ${f.path}
|
|
585
|
+
${f.content}`).join("\n\n");
|
|
586
|
+
}
|
|
587
|
+
if (componentName) {
|
|
588
|
+
const comp = this.components.find((c) => c.definition.name === componentName);
|
|
589
|
+
if (comp) {
|
|
590
|
+
const files = await generator.generateComponent(comp, ctx);
|
|
591
|
+
return files.map((f) => `// ${f.path}
|
|
592
|
+
${f.content}`).join("\n\n");
|
|
593
|
+
}
|
|
594
|
+
return `// Component "${componentName}" not found`;
|
|
595
|
+
}
|
|
596
|
+
return "// Specify a component or type=tokens";
|
|
597
|
+
} catch (err) {
|
|
598
|
+
return `// Error: ${err.message}`;
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
getGeneratedFiles(platform) {
|
|
602
|
+
if (!platform) {
|
|
603
|
+
return Array.from(this.generatedFiles.values()).flat();
|
|
604
|
+
}
|
|
605
|
+
return this.generatedFiles.get(platform) ?? [];
|
|
606
|
+
}
|
|
607
|
+
async updateToken(tokenPath, value, theme) {
|
|
608
|
+
const filePath = theme ? import_node_path.default.resolve(this.cwd, `tokens/${theme}.tokens.json`) : import_node_path.default.resolve(this.cwd, "tokens/semantic.tokens.json");
|
|
609
|
+
try {
|
|
610
|
+
const content = await import_promises.default.readFile(filePath, "utf-8");
|
|
611
|
+
const tree = JSON.parse(content);
|
|
612
|
+
const parts = tokenPath.split(".");
|
|
613
|
+
let current = tree;
|
|
614
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
615
|
+
if (!current[parts[i]]) current[parts[i]] = {};
|
|
616
|
+
current = current[parts[i]];
|
|
617
|
+
}
|
|
618
|
+
const lastKey = parts[parts.length - 1];
|
|
619
|
+
if (current[lastKey] && typeof current[lastKey] === "object" && "$value" in current[lastKey]) {
|
|
620
|
+
current[lastKey].$value = value;
|
|
621
|
+
} else {
|
|
622
|
+
current[lastKey] = { $type: "color", $value: value };
|
|
623
|
+
}
|
|
624
|
+
await import_promises.default.writeFile(filePath, JSON.stringify(tree, null, 2), "utf-8");
|
|
625
|
+
await this.rebuild();
|
|
626
|
+
} catch (err) {
|
|
627
|
+
console.error(`Failed to update token: ${err.message}`);
|
|
628
|
+
throw err;
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
};
|
|
632
|
+
|
|
633
|
+
// src/server/index.ts
|
|
634
|
+
async function startPreviewServer(options = {}) {
|
|
635
|
+
const port = options.port ?? 4400;
|
|
636
|
+
const cwd = process.cwd();
|
|
637
|
+
const builder = new IncrementalBuilder(cwd, options.configPath);
|
|
638
|
+
await builder.initialBuild();
|
|
639
|
+
const server = import_node_http.default.createServer();
|
|
640
|
+
const wss = new import_ws.WebSocketServer({ server });
|
|
641
|
+
setupWsHandler(wss, builder);
|
|
642
|
+
let reactPlugin;
|
|
643
|
+
try {
|
|
644
|
+
const mod = await Promise.resolve().then(() => (init_dist2(), dist_exports));
|
|
645
|
+
reactPlugin = (mod.default ?? mod)();
|
|
646
|
+
} catch {
|
|
647
|
+
}
|
|
648
|
+
const vite = await (0, import_vite.createServer)({
|
|
649
|
+
root: import_node_path3.default.resolve(__dirname, "../client"),
|
|
650
|
+
server: {
|
|
651
|
+
middlewareMode: true,
|
|
652
|
+
hmr: { server }
|
|
653
|
+
},
|
|
654
|
+
plugins: reactPlugin ? [reactPlugin] : [],
|
|
655
|
+
appType: "spa"
|
|
656
|
+
});
|
|
657
|
+
const apiHandler = setupApiRoutes(builder);
|
|
658
|
+
server.on("request", (req, res) => {
|
|
659
|
+
if (req.url?.startsWith("/api/")) {
|
|
660
|
+
apiHandler(req, res);
|
|
661
|
+
} else {
|
|
662
|
+
vite.middlewares(req, res);
|
|
663
|
+
}
|
|
664
|
+
});
|
|
665
|
+
setupWatcher(builder, wss, cwd);
|
|
666
|
+
server.listen(port, () => {
|
|
667
|
+
console.log(`
|
|
668
|
+
\u{1F3A8} RynDesign Preview`);
|
|
669
|
+
console.log(` \u279C Local: http://localhost:${port}/`);
|
|
670
|
+
console.log(` \u279C WS: ws://localhost:${port}/
|
|
671
|
+
`);
|
|
672
|
+
if (options.open) {
|
|
673
|
+
import("child_process").then((cp) => {
|
|
674
|
+
const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
675
|
+
cp.exec(`${cmd} http://localhost:${port}/`);
|
|
676
|
+
}).catch(() => {
|
|
677
|
+
});
|
|
678
|
+
}
|
|
679
|
+
});
|
|
680
|
+
process.on("SIGINT", () => {
|
|
681
|
+
wss.close();
|
|
682
|
+
vite.close();
|
|
683
|
+
server.close();
|
|
684
|
+
process.exit(0);
|
|
685
|
+
});
|
|
686
|
+
}
|
|
687
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
688
|
+
0 && (module.exports = {
|
|
689
|
+
startPreviewServer
|
|
690
|
+
});
|
|
691
|
+
//# sourceMappingURL=index.cjs.map
|