unframer 2.27.2 → 3.0.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.
- package/dist/babel-jsx.js +2 -2
- package/dist/babel-jsx.js.map +1 -1
- package/dist/babel-typedoc.d.ts +39 -0
- package/dist/babel-typedoc.d.ts.map +1 -0
- package/dist/babel-typedoc.js +77 -0
- package/dist/babel-typedoc.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +7 -2
- package/dist/cli.js.map +1 -1
- package/dist/esbuild.d.ts +2 -1
- package/dist/esbuild.d.ts.map +1 -1
- package/dist/esbuild.js +16 -9
- package/dist/esbuild.js.map +1 -1
- package/dist/exporter.d.ts +25 -8
- package/dist/exporter.d.ts.map +1 -1
- package/dist/exporter.js +381 -195
- package/dist/exporter.js.map +1 -1
- package/dist/exporter.test.js +0 -4
- package/dist/exporter.test.js.map +1 -1
- package/dist/framer.js +229 -102
- package/dist/generated/api-client.d.ts +3 -3
- package/dist/generated/api-client.d.ts.map +1 -1
- package/dist/package-manager.d.ts +10 -0
- package/dist/package-manager.d.ts.map +1 -0
- package/dist/package-manager.js +145 -0
- package/dist/package-manager.js.map +1 -0
- package/dist/react.d.ts +32 -0
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +1 -3
- package/dist/react.js.map +1 -1
- package/dist/undici-dispatcher.js +1 -2
- package/dist/undici-dispatcher.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/esm/babel-jsx.js +2 -2
- package/esm/babel-jsx.js.map +1 -1
- package/esm/babel-typedoc.d.ts +39 -0
- package/esm/babel-typedoc.d.ts.map +1 -0
- package/esm/babel-typedoc.js +74 -0
- package/esm/babel-typedoc.js.map +1 -0
- package/esm/cli.d.ts.map +1 -1
- package/esm/cli.js +7 -2
- package/esm/cli.js.map +1 -1
- package/esm/esbuild.d.ts +2 -1
- package/esm/esbuild.d.ts.map +1 -1
- package/esm/esbuild.js +16 -9
- package/esm/esbuild.js.map +1 -1
- package/esm/exporter.d.ts +25 -8
- package/esm/exporter.d.ts.map +1 -1
- package/esm/exporter.js +378 -194
- package/esm/exporter.js.map +1 -1
- package/esm/exporter.test.js +0 -4
- package/esm/exporter.test.js.map +1 -1
- package/esm/framer.js +229 -102
- package/esm/package-manager.d.ts +10 -0
- package/esm/package-manager.d.ts.map +1 -0
- package/esm/package-manager.js +141 -0
- package/esm/package-manager.js.map +1 -0
- package/esm/react.d.ts +32 -0
- package/esm/react.d.ts.map +1 -1
- package/esm/react.js +1 -3
- package/esm/react.js.map +1 -1
- package/esm/undici-dispatcher.js +1 -2
- package/esm/undici-dispatcher.js.map +1 -1
- package/esm/version.d.ts +1 -1
- package/esm/version.d.ts.map +1 -1
- package/esm/version.js +1 -1
- package/esm/version.js.map +1 -1
- package/package.json +5 -4
- package/src/babel-jsx.ts +2 -2
- package/src/babel-typedoc.ts +132 -0
- package/src/cli.ts +7 -2
- package/src/esbuild.ts +17 -12
- package/src/exporter.test.ts +0 -5
- package/src/exporter.ts +448 -237
- package/src/framer.js +237 -103
- package/src/package-manager.ts +164 -0
- package/src/react.tsx +33 -0
- package/src/undici-dispatcher.ts +1 -1
- package/src/version.ts +1 -1
- package/dist/framer.d.ts.map +0 -1
- package/dist/framer.js.map +0 -1
- package/esm/framer-chunks/chunk-22NYTOTD.d.ts +0 -14
- package/esm/framer-chunks/chunk-22NYTOTD.d.ts.map +0 -1
- package/esm/framer-chunks/chunk-22NYTOTD.js +0 -99
- package/esm/framer-chunks/chunk-22NYTOTD.js.map +0 -1
- package/esm/framer-chunks/fontshare-GSJIWLGZ-7BHTUG6K.d.ts +0 -115
- package/esm/framer-chunks/fontshare-GSJIWLGZ-7BHTUG6K.d.ts.map +0 -1
- package/esm/framer-chunks/fontshare-GSJIWLGZ-7BHTUG6K.js +0 -5
- package/esm/framer-chunks/fontshare-GSJIWLGZ-7BHTUG6K.js.map +0 -1
- package/esm/framer-chunks/fontshare-SSHBFVID-ZX5Y6FJ4.d.ts +0 -781
- package/esm/framer-chunks/fontshare-SSHBFVID-ZX5Y6FJ4.d.ts.map +0 -1
- package/esm/framer-chunks/fontshare-SSHBFVID-ZX5Y6FJ4.js +0 -5
- package/esm/framer-chunks/fontshare-SSHBFVID-ZX5Y6FJ4.js.map +0 -1
- package/esm/framer-chunks/fontshare-X6MCIXW5-FUMOBUA2.d.ts +0 -634
- package/esm/framer-chunks/fontshare-X6MCIXW5-FUMOBUA2.d.ts.map +0 -1
- package/esm/framer-chunks/fontshare-X6MCIXW5-FUMOBUA2.js +0 -5
- package/esm/framer-chunks/fontshare-X6MCIXW5-FUMOBUA2.js.map +0 -1
- package/esm/framer-chunks/framer-font-TNC5DMGA-XVG7BST3.d.ts +0 -18
- package/esm/framer-chunks/framer-font-TNC5DMGA-XVG7BST3.d.ts.map +0 -1
- package/esm/framer-chunks/framer-font-TNC5DMGA-XVG7BST3.js +0 -5
- package/esm/framer-chunks/framer-font-TNC5DMGA-XVG7BST3.js.map +0 -1
- package/esm/framer-chunks/google-3GQMHAEU-KEOTHDV6.d.ts +0 -9827
- package/esm/framer-chunks/google-3GQMHAEU-KEOTHDV6.d.ts.map +0 -1
- package/esm/framer-chunks/google-3GQMHAEU-KEOTHDV6.js +0 -5
- package/esm/framer-chunks/google-3GQMHAEU-KEOTHDV6.js.map +0 -1
- package/esm/framer-chunks/google-42BCYVR5-PDCHFNPY.d.ts +0 -3231
- package/esm/framer-chunks/google-42BCYVR5-PDCHFNPY.d.ts.map +0 -1
- package/esm/framer-chunks/google-42BCYVR5-PDCHFNPY.js +0 -5
- package/esm/framer-chunks/google-42BCYVR5-PDCHFNPY.js.map +0 -1
- package/esm/framer-chunks/google-LHIHIYDX-FZZ6UXE7.d.ts +0 -1499
- package/esm/framer-chunks/google-LHIHIYDX-FZZ6UXE7.d.ts.map +0 -1
- package/esm/framer-chunks/google-LHIHIYDX-FZZ6UXE7.js +0 -5
- package/esm/framer-chunks/google-LHIHIYDX-FZZ6UXE7.js.map +0 -1
- package/esm/framer.d.ts.map +0 -1
- package/esm/framer.js.map +0 -1
package/dist/exporter.js
CHANGED
|
@@ -4,19 +4,20 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.bundle = bundle;
|
|
7
|
+
exports.resolvePackageVersion = resolvePackageVersion;
|
|
7
8
|
exports.resolvePackage = resolvePackage;
|
|
8
|
-
exports.checkUnframerVersion = checkUnframerVersion;
|
|
9
9
|
exports.getDarkModeSelector = getDarkModeSelector;
|
|
10
10
|
exports.getStyleTokensCss = getStyleTokensCss;
|
|
11
11
|
exports.findRelativeLinks = findRelativeLinks;
|
|
12
12
|
exports.extractPropControlsUnsafe = extractPropControlsUnsafe;
|
|
13
|
-
exports.
|
|
13
|
+
exports.propControlsToTypedocComments = propControlsToTypedocComments;
|
|
14
14
|
exports.parsePropertyControls = parsePropertyControls;
|
|
15
15
|
exports.extractTokenInfo = extractTokenInfo;
|
|
16
16
|
exports.componentCamelCase = componentCamelCase;
|
|
17
|
+
exports.indentWithTabs = indentWithTabs;
|
|
17
18
|
exports.createExampleComponentCode = createExampleComponentCode;
|
|
19
|
+
exports.isVersionGreater = isVersionGreater;
|
|
18
20
|
const esbuild_1 = require("esbuild");
|
|
19
|
-
const package_json_1 = __importDefault(require("../package.json"));
|
|
20
21
|
const url_1 = __importDefault(require("url"));
|
|
21
22
|
const async_sema_1 = require("async-sema");
|
|
22
23
|
const esbuild_plugins_node_modules_polyfill_1 = require("esbuild-plugins-node-modules-polyfill");
|
|
@@ -27,12 +28,15 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
27
28
|
const path_1 = __importDefault(require("path"));
|
|
28
29
|
const utils_js_1 = require("./utils.js");
|
|
29
30
|
const babel_jsx_js_1 = require("./babel-jsx.js");
|
|
31
|
+
const babel_typedoc_js_1 = require("./babel-typedoc.js");
|
|
30
32
|
const compat_js_1 = require("./compat.js");
|
|
31
33
|
const css_js_1 = require("./css.js");
|
|
32
34
|
const esbuild_2 = require("./esbuild");
|
|
33
35
|
const framer_js_1 = require("./framer.js");
|
|
34
36
|
const sentry_1 = require("./sentry");
|
|
35
37
|
const utils_js_2 = require("./utils.js");
|
|
38
|
+
const package_manager_js_1 = require("./package-manager.js");
|
|
39
|
+
const version_js_1 = require("./version.js");
|
|
36
40
|
const js_api_1 = require("@biomejs/js-api");
|
|
37
41
|
let biome;
|
|
38
42
|
async function bundle({ config, cwd: out = '', watch = false, signal = undefined, }) {
|
|
@@ -43,6 +47,24 @@ async function bundle({ config, cwd: out = '', watch = false, signal = undefined
|
|
|
43
47
|
await fs_1.default.promises.mkdir(out, { recursive: true });
|
|
44
48
|
}
|
|
45
49
|
catch (e) { }
|
|
50
|
+
// Prefix for temporary .js files to avoid HMR issues
|
|
51
|
+
const tempJsPrefix = 'temp_';
|
|
52
|
+
// Helper function to handle file path transformations with temp prefix
|
|
53
|
+
function getFilePaths(filePath, outDir) {
|
|
54
|
+
const baseName = path_1.default.basename(filePath);
|
|
55
|
+
const dirName = path_1.default.dirname(filePath);
|
|
56
|
+
const tempFileName = tempJsPrefix + baseName;
|
|
57
|
+
const tempFilePath = path_1.default.join(dirName, tempFileName);
|
|
58
|
+
return {
|
|
59
|
+
originalPath: filePath,
|
|
60
|
+
tempJsPath: path_1.default.resolve(outDir, tempFilePath),
|
|
61
|
+
finalJsPath: path_1.default.resolve(outDir, filePath),
|
|
62
|
+
jsxPath: path_1.default.resolve(outDir, filePath.replace(/\.js$/, '.jsx')),
|
|
63
|
+
tempFilePath,
|
|
64
|
+
baseName,
|
|
65
|
+
dirName,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
46
68
|
utils_js_2.spinner.start('exporting components...');
|
|
47
69
|
const otherRoutes = Object.fromEntries((config.framerWebPages || []).map((page) => [
|
|
48
70
|
page.webPageId,
|
|
@@ -59,7 +81,7 @@ async function bundle({ config, cwd: out = '', watch = false, signal = undefined
|
|
|
59
81
|
};
|
|
60
82
|
}
|
|
61
83
|
const fn = watch ? esbuild_1.context : fakeContext;
|
|
62
|
-
|
|
84
|
+
const missingPackages = new Set();
|
|
63
85
|
const buildContext = await fn({
|
|
64
86
|
absWorkingDir: out,
|
|
65
87
|
entryPoints: Object.keys(components)
|
|
@@ -88,9 +110,12 @@ async function bundle({ config, cwd: out = '', watch = false, signal = undefined
|
|
|
88
110
|
signal,
|
|
89
111
|
externalPackages: config.externalPackages,
|
|
90
112
|
externalizeNpm: config.allExternal,
|
|
91
|
-
outDir:
|
|
113
|
+
outDir: out,
|
|
92
114
|
onMissingPackage: (e) => {
|
|
93
|
-
|
|
115
|
+
// No longer needed - packages are auto-installed
|
|
116
|
+
},
|
|
117
|
+
onCollectMissingPackage: (pkg) => {
|
|
118
|
+
missingPackages.add(pkg);
|
|
94
119
|
},
|
|
95
120
|
}),
|
|
96
121
|
(0, esbuild_plugins_node_modules_polyfill_1.nodeModulesPolyfillPlugin)({}),
|
|
@@ -105,6 +130,13 @@ async function bundle({ config, cwd: out = '', watch = false, signal = undefined
|
|
|
105
130
|
});
|
|
106
131
|
build.onLoad({ filter: /.*/, namespace: 'virtual' }, async (args) => {
|
|
107
132
|
const name = args.path;
|
|
133
|
+
// Handle virtual routes module
|
|
134
|
+
if (name === '__routes') {
|
|
135
|
+
return {
|
|
136
|
+
contents: `export const routes = ${JSON.stringify(otherRoutes, null, 2)};`,
|
|
137
|
+
loader: 'js',
|
|
138
|
+
};
|
|
139
|
+
}
|
|
108
140
|
const url = components[name];
|
|
109
141
|
const componentBreakpoints = config.componentBreakpoints?.filter((x) => x.componentName === name) || [];
|
|
110
142
|
const brk = breakpointSizes
|
|
@@ -126,6 +158,8 @@ async function bundle({ config, cwd: out = '', watch = false, signal = undefined
|
|
|
126
158
|
...brk.slice(1),
|
|
127
159
|
])
|
|
128
160
|
: {};
|
|
161
|
+
// Use virtual routes module
|
|
162
|
+
const routesImportPath = 'virtual:__routes';
|
|
129
163
|
return {
|
|
130
164
|
contents: /** js **/ `
|
|
131
165
|
'use client'
|
|
@@ -136,30 +170,31 @@ async function bundle({ config, cwd: out = '', watch = false, signal = undefined
|
|
|
136
170
|
signal,
|
|
137
171
|
})}'
|
|
138
172
|
import { WithFramerBreakpoints } from 'unframer'
|
|
173
|
+
import { routes } from '${routesImportPath}'
|
|
139
174
|
const locales = ${JSON.stringify(config.locales) || '[]'}
|
|
140
175
|
const defaultResponsiveVariants = ${JSON.stringify(responsiveVariants, null, 2)}
|
|
141
176
|
|
|
142
|
-
|
|
177
|
+
|
|
178
|
+
function ComponentWithRoot({ locale, ...rest }) {
|
|
143
179
|
return (
|
|
144
180
|
<ContextProviders
|
|
145
|
-
routes={
|
|
146
|
-
children={<
|
|
147
|
-
Component={Component}
|
|
148
|
-
variants={defaultResponsiveVariants}
|
|
149
|
-
{...rest}
|
|
150
|
-
/>}
|
|
181
|
+
routes={routes}
|
|
182
|
+
children={<Component {...rest} />}
|
|
151
183
|
framerSiteId={${JSON.stringify(config.fullFramerProjectId)}}
|
|
152
184
|
locale={locale}
|
|
153
185
|
locales={locales}
|
|
154
186
|
/>
|
|
155
187
|
)
|
|
156
188
|
}
|
|
157
|
-
|
|
158
|
-
export default function ComponentWithRoot({ locale, ...rest }) {
|
|
189
|
+
ComponentWithRoot.Responsive = ({ locale, ...rest }) => {
|
|
159
190
|
return (
|
|
160
191
|
<ContextProviders
|
|
161
|
-
routes={
|
|
162
|
-
children={<
|
|
192
|
+
routes={routes}
|
|
193
|
+
children={<WithFramerBreakpoints
|
|
194
|
+
Component={Component}
|
|
195
|
+
variants={defaultResponsiveVariants}
|
|
196
|
+
{...rest}
|
|
197
|
+
/>}
|
|
163
198
|
framerSiteId={${JSON.stringify(config.fullFramerProjectId)}}
|
|
164
199
|
locale={locale}
|
|
165
200
|
locales={locales}
|
|
@@ -167,6 +202,7 @@ async function bundle({ config, cwd: out = '', watch = false, signal = undefined
|
|
|
167
202
|
)
|
|
168
203
|
}
|
|
169
204
|
Object.assign(ComponentWithRoot, Component)
|
|
205
|
+
export default ComponentWithRoot
|
|
170
206
|
`,
|
|
171
207
|
loader: 'jsx',
|
|
172
208
|
};
|
|
@@ -179,10 +215,27 @@ async function bundle({ config, cwd: out = '', watch = false, signal = undefined
|
|
|
179
215
|
});
|
|
180
216
|
const doNotEditComment = `/* This file was generated by Unframer for Framer project ${config.projectId || ''} "${config.projectName}", do not edit manually */\n`;
|
|
181
217
|
async function rebuild() {
|
|
218
|
+
// Clear missing packages for each rebuild (important for watch mode)
|
|
219
|
+
missingPackages.clear();
|
|
220
|
+
try {
|
|
221
|
+
const installedVersion = await resolvePackageVersion({
|
|
222
|
+
cwd: out,
|
|
223
|
+
pkg: 'unframer',
|
|
224
|
+
});
|
|
225
|
+
if (isVersionGreater(installedVersion || '0.0.0', version_js_1.version || '0.0.0')) {
|
|
226
|
+
// Version mismatch, add with specific version
|
|
227
|
+
missingPackages.add(`unframer@${version_js_1.version}`);
|
|
228
|
+
utils_js_2.spinner.info(`Different unframer version detected (${installedVersion}), will install unframer@${version_js_1.version}`);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
catch (e) {
|
|
232
|
+
// Unframer not installed, add with specific version
|
|
233
|
+
missingPackages.add(`unframer@${version_js_1.version}`);
|
|
234
|
+
utils_js_2.spinner.info(`Missing package detected: unframer@${version_js_1.version}`);
|
|
235
|
+
}
|
|
182
236
|
const prevFiles = await recursiveReaddir(out);
|
|
183
237
|
const buildResult = await buildContext.rebuild().catch((e) => {
|
|
184
238
|
if (e.message.includes('No matching export ')) {
|
|
185
|
-
foundError = true;
|
|
186
239
|
utils_js_2.spinner.error(`esbuild failed to import from an external package, this usually means that the npm package version in Framer is older than the latest.`);
|
|
187
240
|
utils_js_2.spinner.error(`Use --external to make all npm packagess external, then install the right version`);
|
|
188
241
|
process.exit(1);
|
|
@@ -190,105 +243,31 @@ async function bundle({ config, cwd: out = '', watch = false, signal = undefined
|
|
|
190
243
|
throw e;
|
|
191
244
|
});
|
|
192
245
|
utils_js_2.spinner.update('Finished build');
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
!resultPathAbsJs.includes('/chunks/') &&
|
|
206
|
-
!resultPathAbsJs.includes('\\chunks\\')) {
|
|
207
|
-
try {
|
|
208
|
-
let res = (0, core_1.transform)(file.text || '', {
|
|
209
|
-
babelrc: false,
|
|
210
|
-
sourceType: 'module',
|
|
211
|
-
plugins: [
|
|
212
|
-
// babelPluginDeduplicateImports,
|
|
213
|
-
babel_jsx_js_1.babelPluginJsxTransform,
|
|
214
|
-
babel_jsx_js_1.removeJsxExpressionContainer,
|
|
215
|
-
],
|
|
216
|
-
// ast: true,
|
|
217
|
-
// code: false,
|
|
218
|
-
filename: 'x.jsx',
|
|
219
|
-
compact: false,
|
|
220
|
-
sourceMaps: false,
|
|
221
|
-
});
|
|
222
|
-
if (res?.code) {
|
|
223
|
-
if (!biome) {
|
|
224
|
-
biome = await js_api_1.Biome.create({
|
|
225
|
-
distribution: js_api_1.Distribution.NODE,
|
|
226
|
-
});
|
|
227
|
-
}
|
|
228
|
-
let result = biome.formatContent(res.code, {
|
|
229
|
-
filePath: 'example.jsx',
|
|
230
|
-
});
|
|
231
|
-
didFormat = true;
|
|
232
|
-
formatted = result.content;
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
catch (e) {
|
|
236
|
-
(0, sentry_1.notifyError)(e, 'babel transform and format');
|
|
237
|
-
}
|
|
246
|
+
// Install missing packages if any were collected
|
|
247
|
+
if (missingPackages.size > 0) {
|
|
248
|
+
const packagesToInstall = Array.from(missingPackages);
|
|
249
|
+
utils_js_2.logger.log(`Installing missing packages: ${packagesToInstall.join(', ')}`);
|
|
250
|
+
const installResult = await (0, package_manager_js_1.installPackagesBatch)({
|
|
251
|
+
packageNames: packagesToInstall,
|
|
252
|
+
cwd: out,
|
|
253
|
+
isDev: false,
|
|
254
|
+
});
|
|
255
|
+
if (!installResult.success) {
|
|
256
|
+
utils_js_2.spinner.error(`Failed to install packages: ${installResult.error}`);
|
|
257
|
+
// Don't fail the build, just warn
|
|
238
258
|
}
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
// formatted = dprint.format('file.jsx', file.text, {
|
|
244
|
-
// lineWidth: 140,
|
|
245
|
-
// quoteStyle: 'alwaysSingle',
|
|
246
|
-
// trailingCommas: 'always',
|
|
247
|
-
// semiColons: 'always',
|
|
248
|
-
// })
|
|
249
|
-
// }
|
|
250
|
-
// if (tooBig) {
|
|
251
|
-
// spinner.info(
|
|
252
|
-
// `skipping formatting ${path.relative(
|
|
253
|
-
// out,
|
|
254
|
-
// file.path,
|
|
255
|
-
// )}, too big`,
|
|
256
|
-
// )
|
|
257
|
-
// }
|
|
258
|
-
// if (framerWebPages?.length) {
|
|
259
|
-
// codeNew = replaceWebPageIds({
|
|
260
|
-
// code: codeNew,
|
|
261
|
-
// elements: framerWebPages,
|
|
262
|
-
// })
|
|
263
|
-
// }
|
|
264
|
-
// const lines = findRelativeLinks(codeNew)
|
|
265
|
-
// if (lines.length) {
|
|
266
|
-
// spinner.error(
|
|
267
|
-
// `found broken links for ${path.relative(out, file.path)}`,
|
|
268
|
-
// )
|
|
269
|
-
// lines.forEach((line) => {
|
|
270
|
-
// logger.log(`${path.resolve(out, file.path)}:${line + 1}`)
|
|
271
|
-
// })
|
|
272
|
-
// }
|
|
259
|
+
}
|
|
260
|
+
// First, write raw JS files for type extraction with temp prefix
|
|
261
|
+
for (let file of buildResult.outputFiles) {
|
|
262
|
+
const paths = getFilePaths(file.path, out);
|
|
273
263
|
const prefix = `// @ts-nocheck\n` + `/* eslint-disable */\n` + doNotEditComment;
|
|
274
|
-
const codeJsx = prefix + formatted;
|
|
275
264
|
const codeJs = prefix + file.text;
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
// }
|
|
279
|
-
utils_js_2.logger.log(`writing`, path_1.default.relative(out, file.path));
|
|
280
|
-
await fs_1.default.promises.mkdir(path_1.default.dirname(resultPathAbsJsx), {
|
|
265
|
+
utils_js_2.logger.log(`writing temp JS`, path_1.default.relative(out, paths.tempFilePath));
|
|
266
|
+
await fs_1.default.promises.mkdir(path_1.default.dirname(paths.tempJsPath), {
|
|
281
267
|
recursive: true,
|
|
282
268
|
});
|
|
283
|
-
|
|
284
|
-
await fs_1.default.promises.writeFile(resultPathAbsJs, codeJs, 'utf-8');
|
|
285
|
-
}
|
|
286
|
-
if (didFormat) {
|
|
287
|
-
await fs_1.default.promises.writeFile(resultPathAbsJsx, codeJsx, 'utf-8');
|
|
288
|
-
}
|
|
269
|
+
await fs_1.default.promises.writeFile(paths.tempJsPath, codeJs, 'utf-8');
|
|
289
270
|
}
|
|
290
|
-
utils_js_2.spinner.stop();
|
|
291
|
-
await fs_1.default.promises.writeFile(path_1.default.resolve(out, '.cursorignore'), `**/*.js\nchunks\n`, 'utf-8');
|
|
292
271
|
if (!buildResult?.outputFiles) {
|
|
293
272
|
throw new Error('Failed to generate result');
|
|
294
273
|
}
|
|
@@ -304,7 +283,8 @@ async function bundle({ config, cwd: out = '', watch = false, signal = undefined
|
|
|
304
283
|
const name = path_1.default
|
|
305
284
|
.relative(out, file.path)
|
|
306
285
|
.replace(/\.jsx?$/, '');
|
|
307
|
-
const
|
|
286
|
+
const paths = getFilePaths(file.path, out);
|
|
287
|
+
const resultPathAbs = paths.tempJsPath;
|
|
308
288
|
if (!components[name]) {
|
|
309
289
|
return;
|
|
310
290
|
}
|
|
@@ -313,6 +293,7 @@ async function bundle({ config, cwd: out = '', watch = false, signal = undefined
|
|
|
313
293
|
return;
|
|
314
294
|
}
|
|
315
295
|
utils_js_2.logger.log(`extracting types for ${name}`);
|
|
296
|
+
utils_js_2.spinner.info(`Extracting types for component: ${name}`);
|
|
316
297
|
utils_js_2.spinner.update(`Extracting types for ${name}`);
|
|
317
298
|
const { propertyControls, fonts } = await extractPropControlsUnsafe(resultPathAbs, name);
|
|
318
299
|
if (!propertyControls) {
|
|
@@ -322,17 +303,20 @@ async function bundle({ config, cwd: out = '', watch = false, signal = undefined
|
|
|
322
303
|
...x,
|
|
323
304
|
fileName: path_1.default.basename(file.path),
|
|
324
305
|
})));
|
|
325
|
-
const
|
|
306
|
+
const typedocComments = propControlsToTypedocComments({
|
|
326
307
|
controls: propertyControls,
|
|
327
308
|
fileName: name,
|
|
328
309
|
config,
|
|
329
310
|
});
|
|
311
|
+
utils_js_2.logger.log(`Generated TypeDoc comments for ${name}: ${!!typedocComments.headerComment}`);
|
|
330
312
|
await fs_1.default.promises.mkdir(out, { recursive: true });
|
|
331
|
-
|
|
313
|
+
// .d.ts generation removed – types are now injected as typedoc
|
|
314
|
+
// comments directly inside the generated JSX file.
|
|
332
315
|
return {
|
|
333
316
|
propertyControls,
|
|
334
317
|
fonts,
|
|
335
318
|
name,
|
|
319
|
+
typedocComments,
|
|
336
320
|
};
|
|
337
321
|
}
|
|
338
322
|
finally {
|
|
@@ -346,7 +330,6 @@ async function bundle({ config, cwd: out = '', watch = false, signal = undefined
|
|
|
346
330
|
// Ignore error if file doesn't exist or can't be deleted
|
|
347
331
|
}
|
|
348
332
|
});
|
|
349
|
-
// spinner.stop()
|
|
350
333
|
const cssString = doNotEditComment +
|
|
351
334
|
'/* This css file has all the necessary styles to run all your components */\n' +
|
|
352
335
|
'\n' +
|
|
@@ -364,24 +347,27 @@ async function bundle({ config, cwd: out = '', watch = false, signal = undefined
|
|
|
364
347
|
.forEach((x) => utils_js_2.logger.log(x));
|
|
365
348
|
const jsxFiles = buildResult.outputFiles
|
|
366
349
|
.filter((x) => x.path.endsWith('.js') &&
|
|
367
|
-
fs_1.default.existsSync(x.path
|
|
368
|
-
.map((x) => x.path
|
|
350
|
+
fs_1.default.existsSync(getFilePaths(x.path, out).jsxPath))
|
|
351
|
+
.map((x) => getFilePaths(x.path, out).jsxPath);
|
|
369
352
|
const outFiles = buildResult.outputFiles
|
|
370
|
-
.map((x) =>
|
|
353
|
+
.map((x) => {
|
|
354
|
+
const paths = getFilePaths(x.path, out);
|
|
355
|
+
if (x.path.endsWith('.js') && fs_1.default.existsSync(paths.jsxPath)) {
|
|
356
|
+
return null; // Will be handled by jsx files
|
|
357
|
+
}
|
|
358
|
+
return paths.finalJsPath;
|
|
359
|
+
})
|
|
360
|
+
.filter(Boolean)
|
|
371
361
|
.concat([
|
|
372
362
|
path_1.default.resolve(out, 'meta.json'),
|
|
373
363
|
path_1.default.resolve(out, 'tokens.css'),
|
|
374
364
|
path_1.default.resolve(out, '.cursorignore'),
|
|
375
365
|
path_1.default.resolve(out, 'styles.css'),
|
|
376
366
|
])
|
|
377
|
-
.concat(jsxFiles)
|
|
378
|
-
.concat(buildResult.outputFiles.map((x) => path_1.default.resolve(out, x.path.replace(/\.jsx?$/, '.d.ts'))));
|
|
367
|
+
.concat(jsxFiles);
|
|
379
368
|
const filesToDelete = prevFiles
|
|
380
369
|
.filter((x) => !outFiles.includes(x))
|
|
381
|
-
.
|
|
382
|
-
.map((x) => x.path)
|
|
383
|
-
.filter((js) => js.endsWith('.js') &&
|
|
384
|
-
jsxFiles.some((x) => x.startsWith(js))));
|
|
370
|
+
.filter((x) => !x.includes(tempJsPrefix)); // Don't delete temp files here, they're handled separately
|
|
385
371
|
for (let file of filesToDelete) {
|
|
386
372
|
utils_js_2.logger.log('deleting', path_1.default.relative(out, file));
|
|
387
373
|
try {
|
|
@@ -398,12 +384,6 @@ async function bundle({ config, cwd: out = '', watch = false, signal = undefined
|
|
|
398
384
|
if (watch) {
|
|
399
385
|
utils_js_2.logger.log('waiting for components or config changes');
|
|
400
386
|
}
|
|
401
|
-
if (!tokens?.length) {
|
|
402
|
-
const tokensCss = "/* This css file contains your color variables, sometimes these get desynced when updated in Framer so it's good that you copy and paste this snippet into your app css */\n" +
|
|
403
|
-
'/* Bug: https://www.framer.community/c/bugs/color-style-unlinks-when-copying-component-between-projects-resulting-in-potential-value-discrepancy */\n' +
|
|
404
|
-
getTokensCss({ out, result: buildResult });
|
|
405
|
-
await fs_1.default.promises.writeFile(path_1.default.resolve(out, 'tokens.css'), tokensCss, 'utf-8');
|
|
406
|
-
}
|
|
407
387
|
const res = {
|
|
408
388
|
components: Object.entries(components).map(([name, v]) => {
|
|
409
389
|
const propControls = propControlsData.find((x) => x?.name === name);
|
|
@@ -416,6 +396,131 @@ async function bundle({ config, cwd: out = '', watch = false, signal = undefined
|
|
|
416
396
|
};
|
|
417
397
|
}),
|
|
418
398
|
};
|
|
399
|
+
// Process and write JSX files with TypeDoc comments
|
|
400
|
+
utils_js_2.spinner.update('Processing JSX files with TypeDoc comments');
|
|
401
|
+
for (let file of buildResult.outputFiles) {
|
|
402
|
+
const paths = getFilePaths(file.path, out);
|
|
403
|
+
const componentName = path_1.default
|
|
404
|
+
.relative(out, file.path)
|
|
405
|
+
.replace(/\.js$/, '');
|
|
406
|
+
const propData = propControlsData.find((p) => p?.name === componentName);
|
|
407
|
+
const typedocComments = propData?.typedocComments;
|
|
408
|
+
utils_js_2.logger.log(`Processing component: ${componentName}`);
|
|
409
|
+
utils_js_2.spinner.update(`Processing JSX for ${componentName}`);
|
|
410
|
+
if (!propData) {
|
|
411
|
+
utils_js_2.logger.log(` No propData found for ${componentName}`);
|
|
412
|
+
}
|
|
413
|
+
else {
|
|
414
|
+
utils_js_2.logger.log(` PropData found for ${componentName}, has propertyControls: ${!!propData.propertyControls}`);
|
|
415
|
+
if (!typedocComments) {
|
|
416
|
+
utils_js_2.logger.log(` No typedocComments for ${componentName}`);
|
|
417
|
+
}
|
|
418
|
+
else {
|
|
419
|
+
utils_js_2.logger.log(` TypeDoc comments available for ${componentName}`);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
const existing = await fs_1.default.promises
|
|
423
|
+
.readFile(paths.jsxPath, 'utf-8')
|
|
424
|
+
.catch(() => null);
|
|
425
|
+
const tooBigSize = 0.7 * 1024 * 1024;
|
|
426
|
+
let formatted = file.text;
|
|
427
|
+
let tooBig = file.text.length >= tooBigSize;
|
|
428
|
+
let didFormat = false;
|
|
429
|
+
if (config.jsx &&
|
|
430
|
+
!tooBig &&
|
|
431
|
+
!paths.tempJsPath.includes('/chunks/') &&
|
|
432
|
+
!paths.tempJsPath.includes('\\chunks\\')) {
|
|
433
|
+
try {
|
|
434
|
+
const plugins = [
|
|
435
|
+
// babelPluginDeduplicateImports,
|
|
436
|
+
babel_jsx_js_1.babelPluginJsxTransform,
|
|
437
|
+
babel_jsx_js_1.removeJsxExpressionContainer,
|
|
438
|
+
];
|
|
439
|
+
// Add TypeDoc plugin if we have comments for this component
|
|
440
|
+
if (typedocComments) {
|
|
441
|
+
utils_js_2.logger.log(` Adding TypeDoc plugin for ${componentName}`);
|
|
442
|
+
plugins.push((0, babel_typedoc_js_1.babelPluginTypedoc)(typedocComments));
|
|
443
|
+
}
|
|
444
|
+
else {
|
|
445
|
+
utils_js_2.logger.log(` No TypeDoc comments to add for ${componentName}`);
|
|
446
|
+
}
|
|
447
|
+
let res = (0, core_1.transform)(file.text || '', {
|
|
448
|
+
babelrc: false,
|
|
449
|
+
sourceType: 'module',
|
|
450
|
+
parserOpts: {
|
|
451
|
+
plugins: ['jsx'],
|
|
452
|
+
},
|
|
453
|
+
plugins,
|
|
454
|
+
// ast: true,
|
|
455
|
+
// code: false,
|
|
456
|
+
filename: 'x.jsx',
|
|
457
|
+
compact: false,
|
|
458
|
+
sourceMaps: false,
|
|
459
|
+
});
|
|
460
|
+
if (res?.code) {
|
|
461
|
+
if (!biome) {
|
|
462
|
+
biome = await js_api_1.Biome.create({
|
|
463
|
+
distribution: js_api_1.Distribution.NODE,
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
let result = biome.formatContent(res.code, {
|
|
467
|
+
filePath: 'example.jsx',
|
|
468
|
+
});
|
|
469
|
+
didFormat = true;
|
|
470
|
+
formatted = result.content;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
catch (e) {
|
|
474
|
+
(0, sentry_1.notifyError)(e, 'babel transform and format');
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
const prefix = `// @ts-nocheck\n` + `/* eslint-disable */\n` + doNotEditComment;
|
|
478
|
+
const codeJsx = prefix + formatted;
|
|
479
|
+
const codeJs = prefix + file.text;
|
|
480
|
+
utils_js_2.logger.log(`writing`, path_1.default.relative(out, file.path));
|
|
481
|
+
await fs_1.default.promises.mkdir(path_1.default.dirname(paths.jsxPath), {
|
|
482
|
+
recursive: true,
|
|
483
|
+
});
|
|
484
|
+
// Always write the temp .js file for type extraction
|
|
485
|
+
await fs_1.default.promises.writeFile(paths.tempJsPath, codeJs, 'utf-8');
|
|
486
|
+
// Only write .jsx file if it's different from existing or if formatting was done
|
|
487
|
+
if (didFormat && codeJsx !== existing) {
|
|
488
|
+
await fs_1.default.promises.writeFile(paths.jsxPath, codeJsx, 'utf-8');
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
utils_js_2.spinner.stop();
|
|
492
|
+
// await fs.promises.writeFile(
|
|
493
|
+
// path.resolve(out, '.cursorignore'),
|
|
494
|
+
// `**/*.js\nchunks\n`,
|
|
495
|
+
// 'utf-8',
|
|
496
|
+
// )
|
|
497
|
+
// Clean up temp .js files and handle prefixes
|
|
498
|
+
for (let file of buildResult.outputFiles) {
|
|
499
|
+
if (file.path.endsWith('.js')) {
|
|
500
|
+
const paths = getFilePaths(file.path, out);
|
|
501
|
+
if (fs_1.default.existsSync(paths.jsxPath)) {
|
|
502
|
+
// Remove temp .js file if .jsx equivalent exists
|
|
503
|
+
utils_js_2.logger.log('removing temp JS file with JSX equivalent:', path_1.default.relative(out, paths.tempJsPath));
|
|
504
|
+
try {
|
|
505
|
+
await fs_1.default.promises.rm(paths.tempJsPath);
|
|
506
|
+
await fs_1.default.promises.rm(paths.finalJsPath);
|
|
507
|
+
}
|
|
508
|
+
catch (error) {
|
|
509
|
+
// Ignore error if file doesn't exist
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
else {
|
|
513
|
+
// Rename temp .js file to final name if no .jsx equivalent
|
|
514
|
+
utils_js_2.logger.log('renaming temp JS file to final name:', path_1.default.relative(out, paths.tempJsPath), '->', path_1.default.relative(out, paths.finalJsPath));
|
|
515
|
+
try {
|
|
516
|
+
await fs_1.default.promises.rename(paths.tempJsPath, paths.finalJsPath);
|
|
517
|
+
}
|
|
518
|
+
catch (error) {
|
|
519
|
+
// Ignore error if file doesn't exist
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}
|
|
419
524
|
utils_js_2.spinner.info(`Build completed`);
|
|
420
525
|
return res;
|
|
421
526
|
}
|
|
@@ -441,8 +546,11 @@ async function bundle({ config, cwd: out = '', watch = false, signal = undefined
|
|
|
441
546
|
const result = await rebuild();
|
|
442
547
|
console.log();
|
|
443
548
|
console.log();
|
|
444
|
-
const outDirForExample = path_1.default
|
|
445
|
-
|
|
549
|
+
const outDirForExample = path_1.default
|
|
550
|
+
.relative(process.cwd(), out)
|
|
551
|
+
.split(path_1.default.sep)
|
|
552
|
+
.join('/')
|
|
553
|
+
.replace(/^src\//, '') || 'framer'; // remove src so file works inside src
|
|
446
554
|
const { exampleCode } = await createExampleComponentCode({
|
|
447
555
|
outDir: out,
|
|
448
556
|
// buildResult: result,
|
|
@@ -455,38 +563,31 @@ async function bundle({ config, cwd: out = '', watch = false, signal = undefined
|
|
|
455
563
|
});
|
|
456
564
|
await fs_1.default.promises.writeFile(utils_js_2.stackblitzDemoExample, exampleCode);
|
|
457
565
|
}
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
# How to use the Framer components
|
|
566
|
+
console.log((0, utils_js_2.terminalMarkdown)((0, utils_js_1.dedent) `
|
|
567
|
+
# How to use the Framer components
|
|
461
568
|
|
|
462
|
-
|
|
569
|
+
Your components are exported to \`${outDirForExample}\` folder.
|
|
463
570
|
|
|
464
|
-
|
|
465
|
-
npm install unframer
|
|
466
|
-
\`\`\`
|
|
571
|
+
Each component has a \`.Responsive\` variant that allows you to specify different variants for different breakpoints.
|
|
467
572
|
|
|
468
|
-
|
|
573
|
+
You can use the components like this (try copy pasting the code below into your React app):
|
|
469
574
|
|
|
470
|
-
|
|
575
|
+
\`\`\`jsx
|
|
576
|
+
${exampleCode}
|
|
577
|
+
\`\`\`
|
|
471
578
|
|
|
472
|
-
|
|
473
|
-
${exampleCode}
|
|
474
|
-
\`\`\`
|
|
579
|
+
It's very important to import the \`styles.css\` file to include the necessary styles for the components.
|
|
475
580
|
|
|
476
|
-
|
|
581
|
+
To style components you can pass a \`style\` or \`className\` prop (but remember to use !important to increase the specificity).
|
|
477
582
|
|
|
478
|
-
|
|
583
|
+
Read more on GitHub: https://github.com/remorses/unframer
|
|
479
584
|
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
`));
|
|
483
|
-
}
|
|
484
|
-
await checkUnframerVersion({ cwd: out });
|
|
585
|
+
`));
|
|
485
586
|
console.log();
|
|
486
587
|
return { result, rebuild, buildContext };
|
|
487
588
|
}
|
|
488
589
|
const packageVersionCache = new Map();
|
|
489
|
-
function
|
|
590
|
+
function resolvePackageVersion({ cwd, pkg }) {
|
|
490
591
|
if (packageVersionCache.has(pkg)) {
|
|
491
592
|
return Promise.resolve(packageVersionCache.get(pkg));
|
|
492
593
|
}
|
|
@@ -501,7 +602,7 @@ function resolvePackage({ cwd, pkg }) {
|
|
|
501
602
|
cwd,
|
|
502
603
|
}, (error, stdout, stderr) => {
|
|
503
604
|
if (error) {
|
|
504
|
-
|
|
605
|
+
// Package not installed - this is expected and handled by auto-install
|
|
505
606
|
reject(new Error(`${pkg} is not installed in your project`));
|
|
506
607
|
return;
|
|
507
608
|
}
|
|
@@ -511,17 +612,25 @@ function resolvePackage({ cwd, pkg }) {
|
|
|
511
612
|
});
|
|
512
613
|
});
|
|
513
614
|
}
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
const
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
615
|
+
function resolvePackage({ cwd, pkg }) {
|
|
616
|
+
return new Promise((resolve) => {
|
|
617
|
+
const code = `import('${pkg}/package.json', { with: { type: 'json' } }).then(()=>console.log('true')).catch(()=>import('${pkg}').then(()=>console.log('true')).catch(()=>console.log('false')));`;
|
|
618
|
+
const command = [
|
|
619
|
+
JSON.stringify(nodePath),
|
|
620
|
+
'-e',
|
|
621
|
+
JSON.stringify(code),
|
|
622
|
+
].join(' ');
|
|
623
|
+
(0, child_process_1.exec)(command, {
|
|
624
|
+
cwd,
|
|
625
|
+
}, (error, stdout) => {
|
|
626
|
+
if (error) {
|
|
627
|
+
resolve(false);
|
|
628
|
+
return;
|
|
629
|
+
}
|
|
630
|
+
const exists = stdout.trim().split('\n').pop() === 'true';
|
|
631
|
+
resolve(exists);
|
|
632
|
+
});
|
|
633
|
+
});
|
|
525
634
|
}
|
|
526
635
|
function getDarkModeSelector(opts) {
|
|
527
636
|
const { darkModeType = 'class', content } = opts;
|
|
@@ -615,7 +724,7 @@ async function extractPropControlsSafe(text, name) {
|
|
|
615
724
|
utils_js_2.logger.error(`Cannot get property controls for ${name}`, e.stack);
|
|
616
725
|
}
|
|
617
726
|
}
|
|
618
|
-
function getTokensCss({ out, result, }) {
|
|
727
|
+
async function getTokensCss({ out, result, }) {
|
|
619
728
|
const allTokens = [];
|
|
620
729
|
for (let file of result.outputFiles) {
|
|
621
730
|
const code = fs_1.default.readFileSync(path_1.default.resolve(out, file.path), 'utf-8');
|
|
@@ -745,7 +854,11 @@ function safeJsonParse(text) {
|
|
|
745
854
|
return null;
|
|
746
855
|
}
|
|
747
856
|
}
|
|
748
|
-
|
|
857
|
+
/**
|
|
858
|
+
* Generates TypeDoc comments that will be injected into JSX files
|
|
859
|
+
* instead of generating separate .d.ts files
|
|
860
|
+
*/
|
|
861
|
+
function propControlsToTypedocComments({ config, fileName, controls, }) {
|
|
749
862
|
try {
|
|
750
863
|
const types = Object.entries(controls || {})
|
|
751
864
|
.map(([key, value]) => {
|
|
@@ -803,40 +916,76 @@ function propControlsToType({ config, fileName, controls, }) {
|
|
|
803
916
|
if (!name) {
|
|
804
917
|
return '';
|
|
805
918
|
}
|
|
806
|
-
return `
|
|
919
|
+
return ` * ${name}?: ${typescriptType(value)} // ${value.title || name}`;
|
|
807
920
|
})
|
|
808
921
|
.filter(Boolean)
|
|
809
922
|
.join('\n');
|
|
810
923
|
const componentName = componentCamelCase(fileName);
|
|
811
|
-
const
|
|
812
|
-
'children?: React.ReactNode',
|
|
813
|
-
'locale?: Locale',
|
|
814
|
-
'style?: React.CSSProperties',
|
|
815
|
-
'className?: string',
|
|
816
|
-
'id?: string',
|
|
817
|
-
'
|
|
818
|
-
'
|
|
819
|
-
'
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
let
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
924
|
+
const defaultPropsJsDoc = [
|
|
925
|
+
' * children?: React.ReactNode',
|
|
926
|
+
' * locale?: Locale',
|
|
927
|
+
' * style?: React.CSSProperties',
|
|
928
|
+
' * className?: string',
|
|
929
|
+
' * id?: string',
|
|
930
|
+
' * ref?: any',
|
|
931
|
+
' * width?: any',
|
|
932
|
+
' * height?: any',
|
|
933
|
+
' * layoutId?: string',
|
|
934
|
+
].join('\n');
|
|
935
|
+
// Generate header comment with type definitions
|
|
936
|
+
let headerComment = '/**\n';
|
|
937
|
+
headerComment += ' * @typedef Locale\n';
|
|
938
|
+
// Generate union type from config.locales if available
|
|
939
|
+
const localeType = (() => {
|
|
940
|
+
if (config?.locales &&
|
|
941
|
+
Array.isArray(config.locales) &&
|
|
942
|
+
config.locales.length > 0) {
|
|
943
|
+
return config.locales
|
|
944
|
+
.map((locale) => `'${locale.slug}'`)
|
|
945
|
+
.join(' | ');
|
|
946
|
+
}
|
|
947
|
+
return 'string';
|
|
948
|
+
})();
|
|
949
|
+
headerComment += ` * ${localeType}\n`;
|
|
950
|
+
headerComment += ' */\n\n';
|
|
951
|
+
headerComment += '/**\n';
|
|
952
|
+
headerComment +=
|
|
953
|
+
' * @typedef {{\n';
|
|
954
|
+
headerComment += defaultPropsJsDoc;
|
|
955
|
+
if (types) {
|
|
956
|
+
headerComment += '\n' + types;
|
|
957
|
+
}
|
|
958
|
+
headerComment += `\n}} Props\n`;
|
|
959
|
+
headerComment += '\n */\n\n';
|
|
960
|
+
headerComment += '/**\n';
|
|
961
|
+
headerComment += ' * @type {import("unframer").UnframerBreakpoint}\n';
|
|
962
|
+
headerComment += ' * Represents a responsive breakpoint for unframer.\n';
|
|
963
|
+
headerComment += ' */\n\n';
|
|
964
|
+
headerComment += '/**\n';
|
|
965
|
+
headerComment += ' * @typedef VariantsMap\n';
|
|
966
|
+
headerComment +=
|
|
967
|
+
" * Partial record of UnframerBreakpoint to Props.variant, with a mandatory 'base' key.\n";
|
|
968
|
+
headerComment +=
|
|
969
|
+
" * { [key in UnframerBreakpoint]?: Props['variant'] } & { base: Props['variant'] }\n";
|
|
970
|
+
headerComment += ' */';
|
|
971
|
+
// Generate responsive comment
|
|
972
|
+
const responsiveComment = `/**\n * Renders ${componentName} for all breakpoints with a variants map. Variant prop is inferred per breakpoint.\n * @function\n * @param {Omit<Props, 'variant'> & {variants?: VariantsMap}} props\n * @returns {any}\n */`;
|
|
973
|
+
// Generate default export comment - use inline function type instead of referencing undefined type
|
|
974
|
+
const defaultExportComment = `/** @type {function(Props): any} */`;
|
|
975
|
+
return {
|
|
976
|
+
headerComment,
|
|
977
|
+
responsiveComment,
|
|
978
|
+
defaultExportComment,
|
|
979
|
+
};
|
|
836
980
|
}
|
|
837
981
|
catch (e) {
|
|
838
|
-
utils_js_2.logger.error(
|
|
839
|
-
|
|
982
|
+
utils_js_2.logger.error(e.message);
|
|
983
|
+
utils_js_2.logger.error('cannot generate typedoc comments', e.stack);
|
|
984
|
+
return {
|
|
985
|
+
headerComment: '',
|
|
986
|
+
responsiveComment: '',
|
|
987
|
+
defaultExportComment: '',
|
|
988
|
+
};
|
|
840
989
|
}
|
|
841
990
|
}
|
|
842
991
|
function parsePropertyControls(code) {
|
|
@@ -1021,8 +1170,10 @@ function indentWithTabs(str, tabs) {
|
|
|
1021
1170
|
.join('\n');
|
|
1022
1171
|
}
|
|
1023
1172
|
async function createExampleComponentCode({ outDir, config, }) {
|
|
1024
|
-
const outDirForExample = path_1.default
|
|
1173
|
+
const outDirForExample = path_1.default
|
|
1025
1174
|
.relative(process.cwd(), outDir)
|
|
1175
|
+
.split(path_1.default.sep)
|
|
1176
|
+
.join('/')
|
|
1026
1177
|
.replace(/^src\//, ''); // remove src so file works inside src
|
|
1027
1178
|
const instances = config?.componentInstancesInIndexPage?.sort((a, b) => {
|
|
1028
1179
|
// Order first by nodeDepth (lower is better)
|
|
@@ -1068,7 +1219,42 @@ async function createExampleComponentCode({ outDir, config, }) {
|
|
|
1068
1219
|
};
|
|
1069
1220
|
`;
|
|
1070
1221
|
return {
|
|
1222
|
+
outDirForExample,
|
|
1071
1223
|
exampleCode,
|
|
1072
1224
|
};
|
|
1073
1225
|
}
|
|
1226
|
+
/**
|
|
1227
|
+
* Compares two semantic version strings.
|
|
1228
|
+
* Returns true if versionB is greater than versionA.
|
|
1229
|
+
* Handles x.y.z, x.y, x, and optional pre-release (-alpha, etc).
|
|
1230
|
+
*/
|
|
1231
|
+
function isVersionGreater(versionA, versionB) {
|
|
1232
|
+
try {
|
|
1233
|
+
function parseVersion(version) {
|
|
1234
|
+
// Remove pre-release (e.g. -alpha.1)
|
|
1235
|
+
let [core] = version.trim().split('-');
|
|
1236
|
+
return core.split('.').map((x) => parseInt(x, 10));
|
|
1237
|
+
}
|
|
1238
|
+
const [a1 = 0, a2 = 0, a3 = 0] = parseVersion(versionA);
|
|
1239
|
+
const [b1 = 0, b2 = 0, b3 = 0] = parseVersion(versionB);
|
|
1240
|
+
if (b1 > a1)
|
|
1241
|
+
return true;
|
|
1242
|
+
if (b1 < a1)
|
|
1243
|
+
return false;
|
|
1244
|
+
if (b2 > a2)
|
|
1245
|
+
return true;
|
|
1246
|
+
if (b2 < a2)
|
|
1247
|
+
return false;
|
|
1248
|
+
if (b3 > a3)
|
|
1249
|
+
return true;
|
|
1250
|
+
if (b3 < a3)
|
|
1251
|
+
return false;
|
|
1252
|
+
// If all equal, not greater
|
|
1253
|
+
return false;
|
|
1254
|
+
}
|
|
1255
|
+
catch (error) {
|
|
1256
|
+
utils_js_2.spinner.error(`Error comparing versions "${versionA}" and "${versionB}": ${error?.stack || error?.message || error}`);
|
|
1257
|
+
return true;
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1074
1260
|
//# sourceMappingURL=exporter.js.map
|