unframer 2.6.6 → 2.7.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/README.md +9 -46
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +49 -44
- package/dist/cli.js.map +1 -1
- package/dist/css.js +1 -1
- package/dist/css.js.map +1 -1
- package/dist/exporter.d.ts +16 -4
- package/dist/exporter.d.ts.map +1 -1
- package/dist/exporter.js +144 -47
- package/dist/exporter.js.map +1 -1
- package/dist/framer.d.ts.map +1 -1
- package/dist/framer.js +55 -19
- package/dist/framer.js.map +1 -1
- package/dist/utils.d.ts +1 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +7 -0
- package/dist/utils.js.map +1 -1
- package/esm/cli.d.ts.map +1 -1
- package/esm/cli.js +49 -44
- package/esm/cli.js.map +1 -1
- package/esm/css.js +1 -1
- package/esm/css.js.map +1 -1
- package/esm/exporter.d.ts +16 -4
- package/esm/exporter.d.ts.map +1 -1
- package/esm/exporter.js +143 -48
- package/esm/exporter.js.map +1 -1
- package/esm/framer.d.ts.map +1 -1
- package/esm/framer.js +55 -19
- package/esm/framer.js.map +1 -1
- package/esm/utils.d.ts +1 -0
- package/esm/utils.d.ts.map +1 -1
- package/esm/utils.js +6 -0
- package/esm/utils.js.map +1 -1
- package/package.json +7 -5
- package/src/cli.tsx +63 -57
- package/src/css.ts +1 -1
- package/src/exporter.ts +179 -55
- package/src/framer.js +72 -19
- package/src/utils.ts +9 -0
package/esm/utils.d.ts
CHANGED
package/esm/utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAOA,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,4BAEhD;AAGD,eAAO,MAAM,MAAM;;;;CAUlB,CAAA"}
|
package/esm/utils.js
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import pico from 'picocolors';
|
|
2
|
+
import { marked } from 'marked';
|
|
3
|
+
import { markedTerminal } from 'marked-terminal';
|
|
4
|
+
marked.use(markedTerminal());
|
|
5
|
+
export function terminalMarkdown(markdown) {
|
|
6
|
+
return marked(markdown);
|
|
7
|
+
}
|
|
2
8
|
const prefix = '[unframer]';
|
|
3
9
|
export const logger = {
|
|
4
10
|
log(...args) {
|
package/esm/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,YAAY,CAAA;AAE7B,MAAM,MAAM,GAAG,YAAY,CAAA;AAC3B,MAAM,CAAC,MAAM,MAAM,GAAG;IAClB,GAAG,CAAC,GAAG,IAAI;QACP,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAA;IAChC,CAAC;IACD,KAAK,CAAC,GAAG,IAAI;QACT,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;IACtE,CAAC;IACD,KAAK,CAAC,GAAG,IAAI;QACT,OAAO,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;IACtE,CAAC;CACJ,CAAA"}
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,YAAY,CAAA;AAE7B,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC/B,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAEhD,MAAM,CAAC,GAAG,CAAC,cAAc,EAAE,CAAC,CAAA;AAE5B,MAAM,UAAU,gBAAgB,CAAC,QAAgB;IAC7C,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAA;AAC3B,CAAC;AAED,MAAM,MAAM,GAAG,YAAY,CAAA;AAC3B,MAAM,CAAC,MAAM,MAAM,GAAG;IAClB,GAAG,CAAC,GAAG,IAAI;QACP,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAA;IAChC,CAAC;IACD,KAAK,CAAC,GAAG,IAAI;QACT,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;IACtE,CAAC;IACD,KAAK,CAAC,GAAG,IAAI;QACT,OAAO,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;IACtE,CAAC;CACJ,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "unframer",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.7.0",
|
|
4
4
|
"description": "Import Framer components directly in your React app, type safe and customizable",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"repository": "https://github.com/remorses/unframer",
|
|
@@ -44,12 +44,14 @@
|
|
|
44
44
|
"chokidar": "^3.6.0",
|
|
45
45
|
"dedent": "^1.5.3",
|
|
46
46
|
"dprint-node": "^1.0.8",
|
|
47
|
-
"esbuild": "^0.
|
|
47
|
+
"esbuild": "^0.24.0",
|
|
48
48
|
"esbuild-plugin-polyfill-node": "^0.3.0",
|
|
49
49
|
"eventemitter3": "^3.1.2",
|
|
50
50
|
"find-up": "^5.0.0",
|
|
51
51
|
"fs-extra": "^11.2.0",
|
|
52
52
|
"json5": "^2.2.3",
|
|
53
|
+
"marked": "^15.0.3",
|
|
54
|
+
"marked-terminal": "^7.2.1",
|
|
53
55
|
"native-fetch": "^4.0.2",
|
|
54
56
|
"picocolors": "^1.0.1",
|
|
55
57
|
"real-framer-motion": "npm:framer-motion@11.2.10",
|
|
@@ -69,12 +71,12 @@
|
|
|
69
71
|
"@types/fs-extra": "^11.0.4",
|
|
70
72
|
"@types/node": "^22.7.4",
|
|
71
73
|
"@types/react": "^18.3.12",
|
|
72
|
-
"@xmorse/deployment-utils": "^0.2.
|
|
74
|
+
"@xmorse/deployment-utils": "^0.2.18",
|
|
73
75
|
"concurrently": "^8.2.2",
|
|
74
76
|
"openai": "^4.52.7",
|
|
75
77
|
"posthtml": "^0.16.6",
|
|
76
|
-
"react": "19.0.0
|
|
77
|
-
"react-dom": "19.0.0
|
|
78
|
+
"react": "19.0.0",
|
|
79
|
+
"react-dom": "19.0.0",
|
|
78
80
|
"tiktoken": "^1.0.15",
|
|
79
81
|
"typescript": "^5.6.2"
|
|
80
82
|
},
|
package/src/cli.tsx
CHANGED
|
@@ -1,85 +1,90 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { setMaxListeners } from 'events'
|
|
2
2
|
import JSON from 'json5'
|
|
3
|
-
import
|
|
3
|
+
import { bundle, StyleToken } from './exporter.js'
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
import fs from 'fs-extra'
|
|
5
|
+
import { cac } from 'cac'
|
|
7
6
|
import findUp from 'find-up'
|
|
8
|
-
import
|
|
7
|
+
import fs from 'fs-extra'
|
|
9
8
|
import path, { basename } from 'path'
|
|
10
|
-
const configNames = ['unframer.config.json', 'unframer.json']
|
|
11
|
-
import { cac } from 'cac'
|
|
12
|
-
import { logger } from './utils.js'
|
|
13
9
|
import { BreakpointSizes } from './css.js'
|
|
10
|
+
import { logger } from './utils.js'
|
|
11
|
+
const configNames = ['unframer.config.json', 'unframer.json']
|
|
14
12
|
|
|
15
13
|
export const cli = cac('unframer')
|
|
16
14
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
let defaultOutDir = 'framer'
|
|
16
|
+
|
|
17
|
+
function nameToFolder(name: string) {
|
|
18
|
+
return name
|
|
19
|
+
.replace(/[^a-zA-Z0-9]/g, '-') // Replace non-alphanumeric with dash
|
|
20
|
+
.replace(/-+/g, '-') // Replace multiple dashes with single dash
|
|
21
|
+
.replace(/^-|-$/g, '') // Remove leading/trailing dashes
|
|
22
|
+
.toLowerCase()
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
cli.command('[projectId]', 'Run unframer with optional project ID')
|
|
26
|
+
.option('--outDir <dir>', 'Output directory', { default: defaultOutDir })
|
|
27
|
+
.action(async function main(projectId, options) {
|
|
28
|
+
const outDir = options.outDir
|
|
29
|
+
if (projectId) {
|
|
30
|
+
logger.log(`Fetching config for project ${projectId}`)
|
|
31
|
+
const response = await fetch(
|
|
32
|
+
new URL(
|
|
33
|
+
`/api/plugins/reactExportPlugin/project/${projectId}`,
|
|
34
|
+
process.env.UNFRAMER_SERVER_URL || 'https://unframer.co',
|
|
35
|
+
).toString(),
|
|
36
|
+
)
|
|
37
|
+
if (!response.ok) {
|
|
38
|
+
console.error(`Failed to fetch Framer config`)
|
|
39
|
+
logger.error('Response: ' + (await response.text()))
|
|
40
|
+
return
|
|
41
|
+
}
|
|
42
|
+
const data = await response.json()
|
|
43
|
+
return processConfig({
|
|
44
|
+
config: {
|
|
45
|
+
outDir,
|
|
46
|
+
components: Object.fromEntries(
|
|
47
|
+
data.components.map((c) => [
|
|
48
|
+
nameToFolder(c.name),
|
|
49
|
+
c.url,
|
|
50
|
+
]),
|
|
51
|
+
),
|
|
52
|
+
tokens: data.colorStyles,
|
|
53
|
+
},
|
|
54
|
+
watch: false,
|
|
55
|
+
|
|
56
|
+
configBasename: 'remote config',
|
|
57
|
+
signal: new AbortController().signal,
|
|
58
|
+
})
|
|
59
|
+
}
|
|
60
|
+
|
|
20
61
|
fixOldUnframerPath()
|
|
21
62
|
const cwd = process.cwd()
|
|
22
|
-
const watch = process.argv.includes('--watch')
|
|
23
63
|
logger.log(`Looking for ${configNames.join(', ')} in ${cwd}`)
|
|
24
64
|
const configPath = await findUp(configNames, { cwd })
|
|
25
65
|
if (!configPath) {
|
|
26
66
|
logger.log(`No ${configNames.join(', ')} found`)
|
|
27
67
|
return
|
|
28
68
|
}
|
|
29
|
-
|
|
69
|
+
const configBasename = basename(configPath!)
|
|
30
70
|
const configContent = fs.readFileSync(configPath, 'utf8')
|
|
31
71
|
if (!configContent) {
|
|
32
72
|
logger.log(`No ${configBasename} contents found`)
|
|
33
73
|
return
|
|
34
74
|
}
|
|
35
|
-
|
|
75
|
+
const config = JSON.parse(configContent)
|
|
76
|
+
if (outDir !== defaultOutDir) {
|
|
77
|
+
config.outDir = outDir
|
|
78
|
+
}
|
|
36
79
|
|
|
37
80
|
let controller = new AbortController()
|
|
38
81
|
setMaxListeners(0, controller.signal)
|
|
39
82
|
processConfig({
|
|
40
83
|
config,
|
|
41
|
-
watch,
|
|
84
|
+
watch: false,
|
|
42
85
|
signal: controller.signal,
|
|
43
86
|
configBasename,
|
|
44
87
|
})
|
|
45
|
-
if (!watch) {
|
|
46
|
-
return
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const watcher = chokidar.watch(configPath!, {
|
|
50
|
-
persistent: true,
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
watcher.on('change', async (path) => {
|
|
54
|
-
logger.log(`${configBasename} changed`)
|
|
55
|
-
console.log()
|
|
56
|
-
controller.abort()
|
|
57
|
-
|
|
58
|
-
controller = new AbortController()
|
|
59
|
-
setMaxListeners(0, controller.signal)
|
|
60
|
-
|
|
61
|
-
const newConfig = safeJsonParse(
|
|
62
|
-
fs.readFileSync(configPath!, 'utf8'),
|
|
63
|
-
)
|
|
64
|
-
if (!newConfig) {
|
|
65
|
-
logger.log(`Invalid ${configBasename} file`)
|
|
66
|
-
return
|
|
67
|
-
}
|
|
68
|
-
const newNames = getNewNames(config, newConfig)
|
|
69
|
-
if (newNames.length) {
|
|
70
|
-
logger.log(`New components found: ${newNames.join(', ')}`)
|
|
71
|
-
await processConfig({
|
|
72
|
-
config: {
|
|
73
|
-
...newConfig,
|
|
74
|
-
components: pluck(newConfig.components, newNames),
|
|
75
|
-
},
|
|
76
|
-
watch,
|
|
77
|
-
configBasename,
|
|
78
|
-
// signal: controller.signal,
|
|
79
|
-
})
|
|
80
|
-
}
|
|
81
|
-
config = newConfig
|
|
82
|
-
})
|
|
83
88
|
})
|
|
84
89
|
|
|
85
90
|
const defaultConfig = `{
|
|
@@ -105,6 +110,9 @@ function fixOldUnframerPath() {
|
|
|
105
110
|
}
|
|
106
111
|
return false
|
|
107
112
|
}
|
|
113
|
+
const version = require('../package.json').version
|
|
114
|
+
|
|
115
|
+
cli.version(version).help()
|
|
108
116
|
|
|
109
117
|
cli.command('init', 'Init the unframer.config.json config').action(
|
|
110
118
|
async (options) => {
|
|
@@ -118,10 +126,6 @@ cli.command('init', 'Init the unframer.config.json config').action(
|
|
|
118
126
|
},
|
|
119
127
|
)
|
|
120
128
|
|
|
121
|
-
const version = require('../package.json').version
|
|
122
|
-
|
|
123
|
-
cli.version(version).help()
|
|
124
|
-
|
|
125
129
|
function safeJsonParse(json: string) {
|
|
126
130
|
try {
|
|
127
131
|
return JSON.parse(json)
|
|
@@ -155,6 +159,7 @@ type Config = {
|
|
|
155
159
|
[name: string]: string
|
|
156
160
|
}
|
|
157
161
|
breakpoints?: BreakpointSizes
|
|
162
|
+
tokens?: StyleToken[]
|
|
158
163
|
outDir?: string
|
|
159
164
|
}
|
|
160
165
|
async function processConfig({
|
|
@@ -181,6 +186,7 @@ async function processConfig({
|
|
|
181
186
|
breakpoints,
|
|
182
187
|
cwd: installDir,
|
|
183
188
|
watch,
|
|
189
|
+
tokens: config.tokens,
|
|
184
190
|
signal,
|
|
185
191
|
})
|
|
186
192
|
} catch (e: any) {
|
package/src/css.ts
CHANGED
package/src/exporter.ts
CHANGED
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
logFontsUsage,
|
|
28
28
|
} from './css.js'
|
|
29
29
|
import dedent from 'dedent'
|
|
30
|
-
import { logger } from './utils.js'
|
|
30
|
+
import { logger, terminalMarkdown } from './utils.js'
|
|
31
31
|
import {
|
|
32
32
|
esbuildPluginBundleDependencies,
|
|
33
33
|
resolveRedirect,
|
|
@@ -42,10 +42,18 @@ function validateUrl(url: string) {
|
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
export type StyleToken = {
|
|
46
|
+
id: string
|
|
47
|
+
name?: string
|
|
48
|
+
lightColor: string
|
|
49
|
+
darkColor: string
|
|
50
|
+
}
|
|
51
|
+
|
|
45
52
|
export async function bundle({
|
|
46
53
|
cwd: out = '',
|
|
47
54
|
watch = false,
|
|
48
55
|
components = {} as Record<string, string>,
|
|
56
|
+
tokens = [] as StyleToken[],
|
|
49
57
|
breakpoints = {} as BreakpointSizes,
|
|
50
58
|
signal = undefined as AbortSignal | undefined,
|
|
51
59
|
}) {
|
|
@@ -88,7 +96,7 @@ export async function bundle({
|
|
|
88
96
|
esbuildPluginBundleDependencies({
|
|
89
97
|
signal,
|
|
90
98
|
}),
|
|
91
|
-
polyfillNode({}),
|
|
99
|
+
polyfillNode({}) as any,
|
|
92
100
|
{
|
|
93
101
|
name: 'virtual loader',
|
|
94
102
|
setup(build) {
|
|
@@ -143,6 +151,7 @@ export async function bundle({
|
|
|
143
151
|
let codeNew =
|
|
144
152
|
`// @ts-nocheck\n` +
|
|
145
153
|
`/* eslint-disable */\n` +
|
|
154
|
+
'/* This file was generated by Unframer, do not edit manually */\n' +
|
|
146
155
|
dprint.format(resultPathAbs, file.text, {
|
|
147
156
|
lineWidth: 140,
|
|
148
157
|
quoteStyle: 'alwaysSingle',
|
|
@@ -176,9 +185,12 @@ export async function bundle({
|
|
|
176
185
|
JSON.stringify({ type: 'module' }),
|
|
177
186
|
'utf-8',
|
|
178
187
|
)
|
|
188
|
+
if (!result?.outputFiles) {
|
|
189
|
+
throw new Error('Failed to generate result')
|
|
190
|
+
}
|
|
179
191
|
|
|
180
192
|
const propControlsData = await Promise.all(
|
|
181
|
-
result
|
|
193
|
+
result?.outputFiles.map(async (file) => {
|
|
182
194
|
try {
|
|
183
195
|
await sema.acquire()
|
|
184
196
|
const name = path.basename(file.path).replace(/\.js$/, '')
|
|
@@ -217,14 +229,16 @@ export async function bundle({
|
|
|
217
229
|
).finally(() => fs.rmSync(packageJson))
|
|
218
230
|
|
|
219
231
|
const cssString =
|
|
232
|
+
'/* This file was generated by Unframer, do not edit manually */\n' +
|
|
220
233
|
'/* This css file has all the necessary styles to run all your components */\n' +
|
|
234
|
+
'\n' +
|
|
235
|
+
getStyleTokensCss(tokens) +
|
|
221
236
|
breakpointsStyles(breakpoints) +
|
|
222
237
|
'\n\n' +
|
|
223
238
|
combinedCSSRules
|
|
224
239
|
.map((x) => (x?.startsWith(' ') ? dedent(x) : x))
|
|
225
240
|
.join('\n') +
|
|
226
241
|
getFontsStyles(allFonts)
|
|
227
|
-
|
|
228
242
|
fs.writeFileSync(path.resolve(out, 'styles.css'), cssString, 'utf-8')
|
|
229
243
|
|
|
230
244
|
logFontsUsage(allFonts)
|
|
@@ -263,12 +277,17 @@ export async function bundle({
|
|
|
263
277
|
if (watch) {
|
|
264
278
|
logger.log('waiting for components or config changes')
|
|
265
279
|
}
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
280
|
+
if (!tokens?.length) {
|
|
281
|
+
const tokensCss =
|
|
282
|
+
"/* 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" +
|
|
283
|
+
'/* Bug: https://www.framer.community/c/bugs/color-style-unlinks-when-copying-component-between-projects-resulting-in-potential-value-discrepancy */\n' +
|
|
284
|
+
getTokensCss({ out, result })
|
|
285
|
+
fs.writeFileSync(
|
|
286
|
+
path.resolve(out, 'tokens.css'),
|
|
287
|
+
tokensCss,
|
|
288
|
+
'utf-8',
|
|
289
|
+
)
|
|
290
|
+
}
|
|
272
291
|
const res = {
|
|
273
292
|
components: Object.entries(components).map(([name, v]) => {
|
|
274
293
|
const propControls = propControlsData.find(
|
|
@@ -290,54 +309,158 @@ export async function bundle({
|
|
|
290
309
|
if (!watch) {
|
|
291
310
|
const result = await rebuild()
|
|
292
311
|
await buildContext.dispose()
|
|
312
|
+
console.log(
|
|
313
|
+
terminalMarkdown(dedent`
|
|
314
|
+
# How to use the Framer components
|
|
315
|
+
|
|
316
|
+
The components are exported to the \`framer\` directory (or the directory you specified in the config).
|
|
317
|
+
Each component has a \`.Responsive\` variant that allows you to specify different variants for different breakpoints.
|
|
318
|
+
The breakpoints are:
|
|
319
|
+
- base: 0-319px
|
|
320
|
+
- sm: 320-767px
|
|
321
|
+
- md: 768-959px
|
|
322
|
+
- lg: 960-1199px
|
|
323
|
+
- xl: 1200-1535px
|
|
324
|
+
- 2xl: 1536px+
|
|
325
|
+
|
|
326
|
+
You can import the components like this:
|
|
327
|
+
|
|
328
|
+
\`\`\`tsx
|
|
329
|
+
import './framer/styles.css'
|
|
330
|
+
import Logos from './framer/logos'
|
|
331
|
+
|
|
332
|
+
export default function App() {
|
|
333
|
+
return (
|
|
334
|
+
<div>
|
|
335
|
+
<Logos.Responsive
|
|
336
|
+
variants={{
|
|
337
|
+
lg: 'Desktop',
|
|
338
|
+
md: 'Tablet',
|
|
339
|
+
base: 'Mobile',
|
|
340
|
+
}}
|
|
341
|
+
/>
|
|
342
|
+
</div>
|
|
343
|
+
);
|
|
344
|
+
};
|
|
345
|
+
\`\`\`
|
|
346
|
+
|
|
347
|
+
It's very important to import the \`styles.css\` file to include the necessary styles for the components.
|
|
348
|
+
|
|
349
|
+
You can also use the components without the responsive wrapper:
|
|
350
|
+
|
|
351
|
+
\`\`\`tsx
|
|
352
|
+
import './framer/styles.css'
|
|
353
|
+
import Logos from './framer/logos'
|
|
354
|
+
|
|
355
|
+
export default function App() {
|
|
356
|
+
return (
|
|
357
|
+
<div>
|
|
358
|
+
<Logos variant="Desktop" />
|
|
359
|
+
</div>
|
|
360
|
+
);
|
|
361
|
+
};
|
|
362
|
+
\`\`\`
|
|
363
|
+
`),
|
|
364
|
+
)
|
|
293
365
|
return result
|
|
294
366
|
}
|
|
295
367
|
|
|
296
|
-
// when user press ctrl+c dispose
|
|
297
|
-
process.on('SIGINT', async () => {
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
})
|
|
301
|
-
process.on('SIGABRT', async () => {
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
})
|
|
305
|
-
signal?.addEventListener('abort', async () => {
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
})
|
|
368
|
+
// // when user press ctrl+c dispose
|
|
369
|
+
// process.on('SIGINT', async () => {
|
|
370
|
+
// await buildContext.cancel()
|
|
371
|
+
// buildContext.dispose()
|
|
372
|
+
// })
|
|
373
|
+
// process.on('SIGABRT', async () => {
|
|
374
|
+
// await buildContext.cancel()
|
|
375
|
+
// buildContext.dispose()
|
|
376
|
+
// })
|
|
377
|
+
// signal?.addEventListener('abort', async () => {
|
|
378
|
+
// await buildContext.cancel()
|
|
379
|
+
// buildContext.dispose()
|
|
380
|
+
// })
|
|
381
|
+
|
|
382
|
+
// const res = await rebuild()
|
|
383
|
+
|
|
384
|
+
// /**
|
|
385
|
+
// * Get resolved URLs for all components and also wait for 1 second if it took less time than that
|
|
386
|
+
// */
|
|
387
|
+
// const getResolvedUrls = () =>
|
|
388
|
+
// Promise.all([
|
|
389
|
+
// ...Object.values(components).map((u) => {
|
|
390
|
+
// const url = new URL(u)
|
|
391
|
+
// url.searchParams.set('ts', Date.now().toString())
|
|
392
|
+
// return resolveRedirect({ url: url.toString(), signal })
|
|
393
|
+
// }),
|
|
394
|
+
// new Promise((res) => setTimeout(res, 5000)),
|
|
395
|
+
// ])
|
|
396
|
+
// let prevUrls = await getResolvedUrls()
|
|
397
|
+
// while (!signal?.aborted) {
|
|
398
|
+
// const urls = await getResolvedUrls()
|
|
399
|
+
// const changed = urls
|
|
400
|
+
// .map((x, i) => (x !== prevUrls[i] ? i : null))
|
|
401
|
+
// .filter(Boolean)
|
|
402
|
+
// if (!changed?.length) {
|
|
403
|
+
// continue
|
|
404
|
+
// }
|
|
405
|
+
// const changedNames = Object.keys(components).filter((_, i) =>
|
|
406
|
+
// changed.includes(i),
|
|
407
|
+
// )
|
|
408
|
+
// logger.log(`found new component URLs for ${changedNames.join(', ')}`)
|
|
409
|
+
// prevUrls = urls
|
|
410
|
+
// await rebuild()
|
|
411
|
+
// }
|
|
412
|
+
// return res
|
|
413
|
+
}
|
|
309
414
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
])
|
|
324
|
-
let prevUrls = await getResolvedUrls()
|
|
325
|
-
while (!signal?.aborted) {
|
|
326
|
-
const urls = await getResolvedUrls()
|
|
327
|
-
const changed = urls
|
|
328
|
-
.map((x, i) => (x !== prevUrls[i] ? i : null))
|
|
329
|
-
.filter(Boolean)
|
|
330
|
-
if (!changed?.length) {
|
|
331
|
-
continue
|
|
332
|
-
}
|
|
333
|
-
const changedNames = Object.keys(components).filter((_, i) =>
|
|
334
|
-
changed.includes(i),
|
|
415
|
+
export function getDarkModeSelector(opts: {
|
|
416
|
+
darkModeType?: 'class' | 'media'
|
|
417
|
+
content: string
|
|
418
|
+
}) {
|
|
419
|
+
const { darkModeType = 'class', content } = opts
|
|
420
|
+
if (darkModeType === 'media') {
|
|
421
|
+
return (
|
|
422
|
+
'@media (prefers-color-scheme: dark) {\n' +
|
|
423
|
+
' :root {\n' +
|
|
424
|
+
content +
|
|
425
|
+
'\n' +
|
|
426
|
+
' }\n' +
|
|
427
|
+
'}'
|
|
335
428
|
)
|
|
336
|
-
logger.log(`found new component URLs for ${changedNames.join(', ')}`)
|
|
337
|
-
prevUrls = urls
|
|
338
|
-
await rebuild()
|
|
339
429
|
}
|
|
340
|
-
return
|
|
430
|
+
return '.dark:root {\n' + content + '\n' + '}'
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
export function getStyleTokensCss(
|
|
434
|
+
tokens: StyleToken[],
|
|
435
|
+
darkModeType: 'class' | 'media' = 'class',
|
|
436
|
+
) {
|
|
437
|
+
if (!tokens?.length) {
|
|
438
|
+
return ''
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
const lightTokens = tokens
|
|
442
|
+
.map(
|
|
443
|
+
(token) =>
|
|
444
|
+
' --token-' + token.id + ': ' + token.lightColor + ';',
|
|
445
|
+
)
|
|
446
|
+
.join('\n')
|
|
447
|
+
|
|
448
|
+
const darkTokens = tokens
|
|
449
|
+
.map(
|
|
450
|
+
(token) => ' --token-' + token.id + ': ' + token.darkColor + ';',
|
|
451
|
+
)
|
|
452
|
+
.join('\n')
|
|
453
|
+
|
|
454
|
+
return (
|
|
455
|
+
':root {\n' +
|
|
456
|
+
lightTokens +
|
|
457
|
+
'\n' +
|
|
458
|
+
'}\n\n' +
|
|
459
|
+
getDarkModeSelector({
|
|
460
|
+
darkModeType,
|
|
461
|
+
content: darkTokens,
|
|
462
|
+
})
|
|
463
|
+
)
|
|
341
464
|
}
|
|
342
465
|
|
|
343
466
|
function decapitalize(str: string) {
|
|
@@ -615,6 +738,7 @@ export function propControlsToType(controls: PropertyControls, fileName) {
|
|
|
615
738
|
.map((line) => ` ${line}`)
|
|
616
739
|
.join('\n') + '\n'
|
|
617
740
|
let t = ''
|
|
741
|
+
t += '/* This file was generated by Unframer, do not edit manually */\n'
|
|
618
742
|
t += 'import * as React from "react"\n\n'
|
|
619
743
|
t += 'import { UnframerBreakpoint } from "unframer"\n\n'
|
|
620
744
|
t += `export interface Props {\n${defaultPropsTypes}${types}\n}\n\n`
|
|
@@ -669,17 +793,17 @@ export function parsePropertyControls(code: string) {
|
|
|
669
793
|
return propControls.slice(realStart + 1, -1)
|
|
670
794
|
}
|
|
671
795
|
|
|
672
|
-
type
|
|
796
|
+
type ExtractedTokenInfo = {
|
|
673
797
|
tokenName: string
|
|
674
798
|
metadata?: Record<string, any>
|
|
675
799
|
|
|
676
800
|
defaultValue: string
|
|
677
801
|
}
|
|
678
802
|
|
|
679
|
-
export function extractTokenInfo(code: string):
|
|
803
|
+
export function extractTokenInfo(code: string): ExtractedTokenInfo[] {
|
|
680
804
|
const lines = code.split('\n')
|
|
681
805
|
const tokenLines = lines.filter((line) => line.includes('var(--token'))
|
|
682
|
-
const tokens:
|
|
806
|
+
const tokens: ExtractedTokenInfo[] = []
|
|
683
807
|
|
|
684
808
|
for (const line of tokenLines) {
|
|
685
809
|
let startIndex = 0
|