unframer 4.1.8 → 4.2.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 +5 -5
- package/dist/babel-jsx.d.ts +9 -0
- package/dist/babel-jsx.d.ts.map +1 -1
- package/dist/babel-jsx.js +72 -0
- package/dist/babel-jsx.js.map +1 -1
- package/dist/cli.d.ts +2 -2
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +262 -42
- package/dist/cli.js.map +1 -1
- package/dist/css-core.d.ts +50 -0
- package/dist/css-core.d.ts.map +1 -0
- package/dist/css-core.js +231 -0
- package/dist/css-core.js.map +1 -0
- package/dist/css.d.ts +9 -43
- package/dist/css.d.ts.map +1 -1
- package/dist/css.js +9 -232
- package/dist/css.js.map +1 -1
- package/dist/exporter.d.ts +1 -1
- package/dist/exporter.d.ts.map +1 -1
- package/dist/exporter.js +72 -11
- package/dist/exporter.js.map +1 -1
- package/dist/exporter.test.js +78 -0
- package/dist/exporter.test.js.map +1 -1
- package/dist/framer-chunks/{SqliteDatabase-VAKIICSG-R7ZS6CHH.js → SqliteDatabase-VAKIICSG-OPV4MG3Y.js} +5 -4
- package/dist/framer-chunks/{chunk-2DZGP7C2.js → chunk-7ZLQTYXQ.js} +5 -24
- package/dist/framer-chunks/chunk-IKQSD2QC.js +10 -0
- package/dist/framer-chunks/default-blog-sqlite-7ZHEY3GT-TVGUYU6H.js +7 -0
- package/dist/framer-chunks/fontshare-4THNDPMZ-FLLTWCDO.js +7 -0
- package/dist/framer-chunks/fontshare-B2QLD7YB-5V3XZJAH.js +7 -0
- package/dist/framer-chunks/fontshare-O22OBJ3D-FIG3CRN3.js +7 -0
- package/dist/framer-chunks/framer-font-45AI7UCZ-CKGC4MJC.js +7 -0
- package/dist/framer-chunks/google-3FCAKCAC-AM34UPJK.js +7 -0
- package/dist/framer-chunks/google-3SZHWBC6-2VTQEQ7J.js +7 -0
- package/dist/framer-chunks/google-GXDJLGJB-JNEJGCGD.js +7 -0
- package/dist/framer-chunks/sqlite-wasm-FGP37EAY-NO5QVZDI.js +7 -0
- package/dist/framer-chunks/sqlite3-SISQ6ENZ-5WRKGWTY.js +7 -0
- package/dist/framer.d.ts +128 -0
- package/dist/framer.js +820 -428
- package/dist/plugin-mcp-dist/lib/framer.d.ts +1 -7
- package/dist/plugin-mcp-dist/lib/framer.d.ts.map +1 -1
- package/dist/plugin-mcp-dist/lib/framer.js +90 -23
- package/dist/plugin-mcp-dist/lib/framer.js.map +1 -1
- package/dist/plugin-mcp-dist/lib/framer.test.d.ts +2 -0
- package/dist/plugin-mcp-dist/lib/framer.test.d.ts.map +1 -0
- package/dist/plugin-mcp-dist/lib/framer.test.js +214 -0
- package/dist/plugin-mcp-dist/lib/framer.test.js.map +1 -0
- package/dist/plugin-mcp-dist/lib/mcp-handlers.d.ts.map +1 -1
- package/dist/plugin-mcp-dist/lib/mcp-handlers.js +69 -11
- package/dist/plugin-mcp-dist/lib/mcp-handlers.js.map +1 -1
- package/dist/plugin-mcp-dist/lib/mcp.test.js +340 -364
- package/dist/plugin-mcp-dist/lib/mcp.test.js.map +1 -1
- package/dist/plugin-mcp-dist/lib/plugin-websocket.d.ts.map +1 -1
- package/dist/plugin-mcp-dist/lib/plugin-websocket.js +0 -3
- package/dist/plugin-mcp-dist/lib/plugin-websocket.js.map +1 -1
- package/dist/plugin-mcp-dist/lib/react-export.d.ts.map +1 -1
- package/dist/plugin-mcp-dist/lib/react-export.js +79 -61
- package/dist/plugin-mcp-dist/lib/react-export.js.map +1 -1
- package/dist/plugin-mcp-dist/lib/schema.d.ts +8 -0
- package/dist/plugin-mcp-dist/lib/schema.d.ts.map +1 -1
- package/dist/plugin-mcp-dist/lib/schema.js +18 -1
- package/dist/plugin-mcp-dist/lib/schema.js.map +1 -1
- package/dist/plugin-mcp-dist/lib/store.d.ts +1 -1
- package/dist/plugin-mcp-dist/lib/store.d.ts.map +1 -1
- package/dist/plugin-mcp-dist/lib/tunnel-integration.test.d.ts +2 -0
- package/dist/plugin-mcp-dist/lib/tunnel-integration.test.d.ts.map +1 -0
- package/dist/plugin-mcp-dist/lib/tunnel-integration.test.js +147 -0
- package/dist/plugin-mcp-dist/lib/tunnel-integration.test.js.map +1 -0
- package/dist/plugin-mcp-dist/lib/tunnel.d.ts +46 -0
- package/dist/plugin-mcp-dist/lib/tunnel.d.ts.map +1 -0
- package/dist/plugin-mcp-dist/lib/tunnel.js +117 -0
- package/dist/plugin-mcp-dist/lib/tunnel.js.map +1 -0
- package/dist/plugin-mcp-dist/lib/upstream-socket.d.ts +13 -0
- package/dist/plugin-mcp-dist/lib/upstream-socket.d.ts.map +1 -0
- package/dist/plugin-mcp-dist/lib/upstream-socket.js +56 -0
- package/dist/plugin-mcp-dist/lib/upstream-socket.js.map +1 -0
- package/dist/plugin-mcp-dist/lib/upstream-socket.test.d.ts +2 -0
- package/dist/plugin-mcp-dist/lib/upstream-socket.test.d.ts.map +1 -0
- package/dist/plugin-mcp-dist/lib/upstream-socket.test.js +212 -0
- package/dist/plugin-mcp-dist/lib/upstream-socket.test.js.map +1 -0
- package/dist/plugin-mcp-dist/lib/utils.d.ts +1 -9
- package/dist/plugin-mcp-dist/lib/utils.d.ts.map +1 -1
- package/dist/plugin-mcp-dist/lib/utils.js +13 -9
- package/dist/plugin-mcp-dist/lib/utils.js.map +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +7 -13
- package/dist/react.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +7 -8
- package/src/babel-jsx.ts +99 -0
- package/src/cli.ts +295 -42
- package/src/css-core.ts +277 -0
- package/src/css.tsx +10 -276
- package/src/exporter.test.ts +82 -0
- package/src/exporter.ts +92 -11
- package/src/framer.d.ts +128 -0
- package/src/framer.js +820 -428
- package/src/plugin-mcp-dist/lib/framer.d.ts +2 -5
- package/src/plugin-mcp-dist/lib/framer.d.ts.map +1 -1
- package/src/plugin-mcp-dist/lib/framer.js +90 -23
- package/src/plugin-mcp-dist/lib/framer.js.map +1 -1
- package/src/plugin-mcp-dist/lib/framer.test.d.ts +2 -0
- package/src/plugin-mcp-dist/lib/framer.test.d.ts.map +1 -0
- package/src/plugin-mcp-dist/lib/framer.test.js +213 -0
- package/src/plugin-mcp-dist/lib/framer.test.js.map +1 -0
- package/src/plugin-mcp-dist/lib/mcp-handlers.d.ts +2 -2
- package/src/plugin-mcp-dist/lib/mcp-handlers.d.ts.map +1 -1
- package/src/plugin-mcp-dist/lib/mcp-handlers.js +69 -11
- package/src/plugin-mcp-dist/lib/mcp-handlers.js.map +1 -1
- package/src/plugin-mcp-dist/lib/mcp.test.js +340 -364
- package/src/plugin-mcp-dist/lib/mcp.test.js.map +1 -1
- package/src/plugin-mcp-dist/lib/plugin-websocket.d.ts.map +1 -1
- package/src/plugin-mcp-dist/lib/plugin-websocket.js +0 -3
- package/src/plugin-mcp-dist/lib/plugin-websocket.js.map +1 -1
- package/src/plugin-mcp-dist/lib/react-export.d.ts +1 -1
- package/src/plugin-mcp-dist/lib/react-export.d.ts.map +1 -1
- package/src/plugin-mcp-dist/lib/react-export.js +79 -61
- package/src/plugin-mcp-dist/lib/react-export.js.map +1 -1
- package/src/plugin-mcp-dist/lib/schema.d.ts +11 -3
- package/src/plugin-mcp-dist/lib/schema.d.ts.map +1 -1
- package/src/plugin-mcp-dist/lib/schema.js +18 -1
- package/src/plugin-mcp-dist/lib/schema.js.map +1 -1
- package/src/plugin-mcp-dist/lib/tunnel-integration.test.d.ts +2 -0
- package/src/plugin-mcp-dist/lib/tunnel-integration.test.d.ts.map +1 -0
- package/src/plugin-mcp-dist/lib/tunnel-integration.test.js +146 -0
- package/src/plugin-mcp-dist/lib/tunnel-integration.test.js.map +1 -0
- package/src/plugin-mcp-dist/lib/tunnel.d.ts +55 -0
- package/src/plugin-mcp-dist/lib/tunnel.d.ts.map +1 -0
- package/src/plugin-mcp-dist/lib/tunnel.js +116 -0
- package/src/plugin-mcp-dist/lib/tunnel.js.map +1 -0
- package/src/plugin-mcp-dist/lib/upstream-socket.d.ts +28 -0
- package/src/plugin-mcp-dist/lib/upstream-socket.d.ts.map +1 -0
- package/src/plugin-mcp-dist/lib/upstream-socket.js +55 -0
- package/src/plugin-mcp-dist/lib/upstream-socket.js.map +1 -0
- package/src/plugin-mcp-dist/lib/upstream-socket.test.d.ts +5 -0
- package/src/plugin-mcp-dist/lib/upstream-socket.test.d.ts.map +1 -0
- package/src/plugin-mcp-dist/lib/upstream-socket.test.js +211 -0
- package/src/plugin-mcp-dist/lib/upstream-socket.test.js.map +1 -0
- package/src/plugin-mcp-dist/lib/utils.d.ts +2 -2
- package/src/plugin-mcp-dist/lib/utils.d.ts.map +1 -1
- package/src/plugin-mcp-dist/lib/utils.js +13 -9
- package/src/plugin-mcp-dist/lib/utils.js.map +1 -1
- package/src/react.tsx +7 -19
- package/src/styles/framer.css +34 -64
- package/src/version.ts +1 -1
- package/dist/framer-chunks/default-blog-sqlite-7ZHEY3GT-27R5KAAW.js +0 -9
- package/dist/framer-chunks/fontshare-4THNDPMZ-BJQGNHXN.js +0 -27099
- package/dist/framer-chunks/fontshare-B2QLD7YB-4BZEAA37.js +0 -119
- package/dist/framer-chunks/fontshare-O22OBJ3D-ALBQLFE5.js +0 -825
- package/dist/framer-chunks/framer-font-45AI7UCZ-LU7DEIDM.js +0 -7
- package/dist/framer-chunks/google-3FCAKCAC-P5EL6KGL.js +0 -623876
- package/dist/framer-chunks/google-3SZHWBC6-OBXS3UIH.js +0 -1627
- package/dist/framer-chunks/google-GXDJLGJB-HHIXFE4M.js +0 -6885
- package/dist/framer-chunks/sqlite-wasm-FGP37EAY-HR6PIAJQ.js +0 -11479
- package/dist/framer-chunks/sqlite3-SISQ6ENZ-KMXYXSSV.js +0 -9
- package/dist/generated/api-client.d.ts +0 -21
- package/dist/generated/api-client.d.ts.map +0 -1
- package/dist/generated/api-client.js +0 -27
- package/dist/generated/api-client.js.map +0 -1
- package/src/generated/api-client.d.ts +0 -1238
- package/src/generated/api-client.js +0 -26
package/dist/css.js
CHANGED
|
@@ -1,247 +1,25 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import dedent from 'string-dedent';
|
|
3
2
|
import { withCSS as withCSSOriginal } from './framer.js';
|
|
4
|
-
|
|
5
|
-
// New fonts have cssFamilyName, old fonts have family
|
|
6
|
-
return font.cssFamilyName || font.family;
|
|
7
|
-
}
|
|
8
|
-
function deduplicateByKey(arr, key) {
|
|
9
|
-
let map = new Map();
|
|
10
|
-
for (let item of arr) {
|
|
11
|
-
let value = key(item);
|
|
12
|
-
if (map.has(value)) {
|
|
13
|
-
continue;
|
|
14
|
-
}
|
|
15
|
-
map.set(value, item);
|
|
16
|
-
}
|
|
17
|
-
return Array.from(map.values());
|
|
18
|
-
}
|
|
19
|
-
export function logFontsUsage(fontsBundles) {
|
|
20
|
-
if (!fontsBundles.length) {
|
|
21
|
-
return '';
|
|
22
|
-
}
|
|
23
|
-
let familyToFilenames = new Map();
|
|
24
|
-
for (let fontDefBundle of fontsBundles) {
|
|
25
|
-
let filename = fontDefBundle.fileName;
|
|
26
|
-
for (let font of fontDefBundle.fonts) {
|
|
27
|
-
const familyName = getFontFamilyName(font);
|
|
28
|
-
if (!familyName)
|
|
29
|
-
continue;
|
|
30
|
-
if (familyToFilenames.has(familyName)) {
|
|
31
|
-
familyToFilenames.get(familyName).add(filename);
|
|
32
|
-
}
|
|
33
|
-
else {
|
|
34
|
-
familyToFilenames.set(familyName, new Set([filename]));
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
let str = `There are ${familyToFilenames.size} fonts used:\n`;
|
|
39
|
-
for (let [family, filenames] of familyToFilenames.entries()) {
|
|
40
|
-
str += `${JSON.stringify(family)}, used by\n`;
|
|
41
|
-
for (let filename of filenames) {
|
|
42
|
-
str += ` - ${filename}\n`;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
return str;
|
|
46
|
-
}
|
|
47
|
-
export function getFontsStyles(_fontsDefs) {
|
|
48
|
-
if (!_fontsDefs.length) {
|
|
49
|
-
return '';
|
|
50
|
-
}
|
|
51
|
-
let urlToFilenames = new Map();
|
|
52
|
-
for (let fontDefBundle of _fontsDefs) {
|
|
53
|
-
let filename = fontDefBundle.fileName;
|
|
54
|
-
for (let font of fontDefBundle.fonts) {
|
|
55
|
-
if (urlToFilenames.has(font.url)) {
|
|
56
|
-
urlToFilenames.get(font.url).add(filename);
|
|
57
|
-
}
|
|
58
|
-
else {
|
|
59
|
-
urlToFilenames.set(font.url, new Set([filename]));
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
const allFonts = deduplicateByKey(_fontsDefs.flatMap((x) => x.fonts), (x) => x?.url)
|
|
64
|
-
.filter((x) => {
|
|
65
|
-
if (!x.url)
|
|
66
|
-
return false;
|
|
67
|
-
const familyName = getFontFamilyName(x);
|
|
68
|
-
if (!familyName) {
|
|
69
|
-
console.log('Font missing family field:', JSON.stringify(x, null, 2));
|
|
70
|
-
return false;
|
|
71
|
-
}
|
|
72
|
-
return true;
|
|
73
|
-
})
|
|
74
|
-
.sort((a, b) => a.url.localeCompare(b.url));
|
|
75
|
-
// group fonts by the filenames users
|
|
76
|
-
const grouped = groupBy(allFonts, (x) => {
|
|
77
|
-
return [...(urlToFilenames.get(x.url) || [])].sort().join(', ');
|
|
78
|
-
});
|
|
79
|
-
let str = '\n\n';
|
|
80
|
-
for (let [groupComment, fonts] of grouped.entries()) {
|
|
81
|
-
fonts = sortByKey(fonts, (x) => x.url);
|
|
82
|
-
str += `/* used by ${groupComment} */\n`;
|
|
83
|
-
str +=
|
|
84
|
-
'\n' +
|
|
85
|
-
fonts
|
|
86
|
-
.map((x) => {
|
|
87
|
-
let str = '';
|
|
88
|
-
const familyName = getFontFamilyName(x);
|
|
89
|
-
str += dedent `
|
|
90
|
-
@font-face {
|
|
91
|
-
font-family: "${familyName}";
|
|
92
|
-
src: url('${x.url}');\n
|
|
93
|
-
`;
|
|
94
|
-
if (x.style) {
|
|
95
|
-
str += ` font-style: ${x.style};\n`;
|
|
96
|
-
}
|
|
97
|
-
if (x.weight) {
|
|
98
|
-
str += ` font-weight: ${x.weight};\n`;
|
|
99
|
-
}
|
|
100
|
-
if (x.unicodeRange) {
|
|
101
|
-
str += ` unicode-range: ${x.unicodeRange};\n`;
|
|
102
|
-
}
|
|
103
|
-
str += `}\n`;
|
|
104
|
-
return str;
|
|
105
|
-
})
|
|
106
|
-
.join('\n') +
|
|
107
|
-
'\n';
|
|
108
|
-
}
|
|
109
|
-
return str;
|
|
110
|
-
}
|
|
111
|
-
export const defaultBreakpointSizes = {
|
|
112
|
-
base: 0,
|
|
113
|
-
sm: 320,
|
|
114
|
-
md: 768,
|
|
115
|
-
lg: 960,
|
|
116
|
-
xl: 1200,
|
|
117
|
-
'2xl': 1536,
|
|
118
|
-
};
|
|
119
|
-
// @deprecated TODO remove this in future releases
|
|
120
|
-
export const breakpointsStylesLegacy = (breakpointSizes) => {
|
|
121
|
-
breakpointSizes = { ...defaultBreakpointSizes, ...breakpointSizes };
|
|
122
|
-
return /* css */ `
|
|
123
|
-
/* Base */
|
|
124
|
-
@media (min-width: ${breakpointSizes.base}px) and (max-width: ${breakpointSizes.sm - 1}px) {
|
|
125
|
-
.unframer-hidden.unframer-base {
|
|
126
|
-
display: contents;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/* Small */
|
|
131
|
-
@media (min-width: ${breakpointSizes.sm}px) and (max-width: ${breakpointSizes.md - 1}px) {
|
|
132
|
-
.unframer-hidden.unframer-sm {
|
|
133
|
-
display: contents;
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/* Medium */
|
|
138
|
-
@media (min-width: ${breakpointSizes.md}px) and (max-width: ${breakpointSizes.lg - 1}px) {
|
|
139
|
-
.unframer-hidden.unframer-md {
|
|
140
|
-
display: contents;
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/* Large */
|
|
145
|
-
@media (min-width: ${breakpointSizes.lg}px) and (max-width: ${breakpointSizes.xl - 1}px) {
|
|
146
|
-
.unframer-hidden.unframer-lg {
|
|
147
|
-
display: contents;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/* Extra Large */
|
|
152
|
-
@media (min-width: ${breakpointSizes.xl}px) and (max-width: ${breakpointSizes['2xl'] - 1}px) {
|
|
153
|
-
.unframer-hidden.unframer-xl {
|
|
154
|
-
display: contents;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
/* 2 Extra Large */
|
|
159
|
-
@media (min-width: ${breakpointSizes['2xl']}px) {
|
|
160
|
-
.unframer-hidden.unframer-2xl {
|
|
161
|
-
display: contents;
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
.unframer-hidden {
|
|
166
|
-
display: none;
|
|
167
|
-
}
|
|
168
|
-
`;
|
|
169
|
-
};
|
|
170
|
-
export const breakpointsStyles = (breakpointSizes) => {
|
|
171
|
-
breakpointSizes = { ...defaultBreakpointSizes, ...breakpointSizes };
|
|
172
|
-
return /* css */ `
|
|
173
|
-
|
|
174
|
-
/* Base */
|
|
175
|
-
@media (min-width: ${breakpointSizes.base}px) and (max-width: ${breakpointSizes.sm - 1}px) {
|
|
176
|
-
.unframer-hidden:not(.unframer-base) {
|
|
177
|
-
display: none !important;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
/* Small */
|
|
182
|
-
@media (min-width: ${breakpointSizes.sm}px) and (max-width: ${breakpointSizes.md - 1}px) {
|
|
183
|
-
.unframer-hidden:not(.unframer-sm) {
|
|
184
|
-
display: none !important;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
/* Medium */
|
|
189
|
-
@media (min-width: ${breakpointSizes.md}px) and (max-width: ${breakpointSizes.lg - 1}px) {
|
|
190
|
-
.unframer-hidden:not(.unframer-md) {
|
|
191
|
-
display: none !important;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
/* Large */
|
|
196
|
-
@media (min-width: ${breakpointSizes.lg}px) and (max-width: ${breakpointSizes.xl - 1}px) {
|
|
197
|
-
.unframer-hidden:not(.unframer-lg) {
|
|
198
|
-
display: none !important;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
/* Extra Large */
|
|
203
|
-
@media (min-width: ${breakpointSizes.xl}px) and (max-width: ${breakpointSizes['2xl'] - 1}px) {
|
|
204
|
-
.unframer-hidden:not(.unframer-xl) {
|
|
205
|
-
display: none !important;
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
/* 2 Extra Large */
|
|
210
|
-
@media (min-width: ${breakpointSizes['2xl']}px) {
|
|
211
|
-
.unframer-hidden:not(.unframer-2xl) {
|
|
212
|
-
display: none !important;
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
`;
|
|
216
|
-
};
|
|
217
|
-
export function groupBy(arr, key) {
|
|
218
|
-
const map = new Map();
|
|
219
|
-
for (let item of arr) {
|
|
220
|
-
const k = key(item);
|
|
221
|
-
if (!map.has(k)) {
|
|
222
|
-
map.set(k, []);
|
|
223
|
-
}
|
|
224
|
-
map.get(k)?.push(item);
|
|
225
|
-
}
|
|
226
|
-
return map;
|
|
227
|
-
}
|
|
228
|
-
function sortByKey(arr, key) {
|
|
229
|
-
return arr.slice().sort((a, b) => key(a).localeCompare(key(b)));
|
|
230
|
-
}
|
|
3
|
+
export * from './css-core.js';
|
|
231
4
|
/**
|
|
232
5
|
* Custom withCSS function that restores the previous behavior
|
|
233
|
-
* of rendering inline style tags instead of using cssCollector
|
|
6
|
+
* of rendering inline style tags instead of using cssCollector.
|
|
7
|
+
*
|
|
8
|
+
* On the client we return withCSSOriginal so the component tree structure
|
|
9
|
+
* matches what framer.js internal components produce (just <Component/>,
|
|
10
|
+
* no Fragment wrapper). On the server we render <style> + <Component>
|
|
11
|
+
* inside a Fragment to inject CSS into the SSR HTML. The tree differs
|
|
12
|
+
* between server and client but suppressHydrationWarning on the Component
|
|
13
|
+
* handles the mismatch.
|
|
234
14
|
*/
|
|
235
15
|
export function withCSS(Component, escapedCSS, componentSerializationId) {
|
|
236
16
|
const framerCSSMarker = 'data-framer-css-ssr';
|
|
237
17
|
if (typeof window !== 'undefined' && typeof window.document !== 'undefined')
|
|
238
18
|
return withCSSOriginal(Component, escapedCSS, componentSerializationId || '');
|
|
239
19
|
return (props) => {
|
|
240
|
-
// Check if we're in SSR mode
|
|
241
20
|
const isBrowser = typeof window !== 'undefined' &&
|
|
242
21
|
typeof window.document !== 'undefined';
|
|
243
22
|
if (!isBrowser) {
|
|
244
|
-
// Server-side: render style tags like the old behavior
|
|
245
23
|
const id = componentSerializationId;
|
|
246
24
|
const cssContent = typeof escapedCSS === 'function'
|
|
247
25
|
? escapedCSS('EXPORT')
|
|
@@ -252,7 +30,6 @@ export function withCSS(Component, escapedCSS, componentSerializationId) {
|
|
|
252
30
|
_jsx("style", { [framerCSSMarker]: true, "data-framer-component": id, dangerouslySetInnerHTML: { __html: cssContent } }), _jsx(Component, { ...props })
|
|
253
31
|
] }));
|
|
254
32
|
}
|
|
255
|
-
// Client-side: just render the component
|
|
256
33
|
return _jsx(Component, { ...props });
|
|
257
34
|
};
|
|
258
35
|
}
|
package/dist/css.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"css.js","sourceRoot":"","sources":["../src/css.tsx"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"css.js","sourceRoot":"","sources":["../src/css.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,aAAa,CAAA;AAExD,cAAc,eAAe,CAAA;AAE7B;;;;;;;;;;GAUG;AACH,MAAM,UAAU,OAAO,CACnB,SAAc,EACd,UAAe,EACf,wBAAiC,EACnC;IACE,MAAM,eAAe,GAAG,qBAAqB,CAAA;IAE7C,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,OAAO,MAAM,CAAC,QAAQ,KAAK,WAAW;QACvE,OAAO,eAAe,CAAC,SAAS,EAAE,UAAU,EAAE,wBAAwB,IAAI,EAAE,CAAC,CAAA;IAEjF,OAAO,CAAC,KAAU,EAAE,EAAE,CAAC;QACnB,MAAM,SAAS,GACX,OAAO,MAAM,KAAK,WAAW;YAC7B,OAAO,MAAM,CAAC,QAAQ,KAAK,WAAW,CAAA;QAE1C,IAAI,CAAC,SAAS,EAAE,CAAC;YACb,MAAM,EAAE,GAAG,wBAAwB,CAAA;YACnC,MAAM,UAAU,GACZ,OAAO,UAAU,KAAK,UAAU;gBAC5B,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC;gBACtB,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC;oBACzB,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;oBACvB,CAAC,CAAC,UAAU,CAAA;YAEtB,OAAO,CACH;oBACI,gBACU,CAAC,eAAe,CAAC,EAAE,IAAI,2BACN,EAAE,EACzB,uBAAuB,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,GACjD,EACF,KAAC,SAAS,OAAK,KAAK,GAAI;oBACzB,CACN,CAAA;QACL,CAAC;QAED,OAAO,KAAC,SAAS,OAAK,KAAK,GAAI,CAAA;IAAA,CAClC,CAAA;AAAA,CACJ"}
|
package/dist/exporter.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { BuildResult, type BuildOptions } from 'esbuild';
|
|
2
2
|
import { Config } from './cli.js';
|
|
3
|
-
import { ComponentFontBundle } from './css.js';
|
|
3
|
+
import { ComponentFontBundle } from './css-core.js';
|
|
4
4
|
import type { PropertyControls } from './framer-types.js';
|
|
5
5
|
export type StyleToken = {
|
|
6
6
|
id: string;
|
package/dist/exporter.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exporter.d.ts","sourceRoot":"","sources":["../src/exporter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAkB,KAAK,YAAY,EAAE,MAAM,SAAS,CAAA;AAIxE,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"exporter.d.ts","sourceRoot":"","sources":["../src/exporter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAkB,KAAK,YAAY,EAAE,MAAM,SAAS,CAAA;AAIxE,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AAoBjC,OAAO,EACH,mBAAmB,EAOtB,MAAM,eAAe,CAAA;AAUtB,OAAO,KAAK,EAAsB,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AA6C7E,MAAM,MAAM,UAAU,GAAG;IACrB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;CACpB,CAAA;AAkBD,wBAAsB,MAAM,CAAC,EACzB,MAAM,EACN,GAAG,EAAE,GAAQ,EACb,KAAa,EACb,MAA6C,EAC7C,QAAgB,EACnB,EAAE;IACC,MAAM,EAAE,MAAM,CAAA;IACd,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACrB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAizBA;AAID,wBAAgB,qBAAqB,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE;;;CAAA,+BA+BjD;AAED,wBAAgB,cAAc,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE;;;CAAA,oBAyB1C;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE;IACtC,YAAY,CAAC,EAAE,OAAO,GAAG,OAAO,CAAA;IAChC,OAAO,EAAE,MAAM,CAAA;CAClB,UAaA;AAiBD,wBAAgB,iBAAiB,CAC7B,MAAM,EAAE,UAAU,EAAE,EACpB,YAAY,GAAE,OAAO,GAAG,OAAiB,UAyF5C;AACD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,YAY7C;AAID,wBAAsB,yBAAyB,CAC3C,QAAQ,KAAA,EACR,IAAI,KAAA,GACL,OAAO,CAAC;IACP,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;IACnC,KAAK,CAAC,EAAE,mBAAmB,EAAE,CAAA;CAChC,CAAC,CAsED;AAWD,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,iBAqCjD;AAED,KAAK,kBAAkB,GAAG;IACtB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAE9B,YAAY,EAAE,MAAM,CAAA;CACvB,CAAA;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB,EAAE,CA2DnE;AAsBD,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,UAMvD;AAED,wBAAsB,0BAA0B,CAAC,EAC7C,MAAM,EACN,MAAM,EACT,EAAE;IACC,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;CACjB;;;GAwHA;AAED,KAAK,YAAY,GAAG;IAChB,UAAU,EAAE,KAAK,CAAC;QACd,iBAAiB,EAAE,MAAM,CAAA;QACzB,IAAI,EAAE,MAAM,CAAA;QACZ,GAAG,EAAE,MAAM,CAAA;QACX,aAAa,EAAE,MAAM,CAAA;QACrB,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;KACtC,CAAC,CAAA;CACL,CAAA;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAyB5E"}
|
package/dist/exporter.js
CHANGED
|
@@ -3,16 +3,15 @@ import url from 'url';
|
|
|
3
3
|
import { createRequire } from 'node:module';
|
|
4
4
|
const require = createRequire(import.meta.url);
|
|
5
5
|
import { Sema } from 'async-sema';
|
|
6
|
-
import { nodeModulesPolyfillPlugin } from 'esbuild-plugins-node-modules-polyfill';
|
|
7
6
|
import { transform } from '@babel/core';
|
|
8
7
|
import { exec } from 'child_process';
|
|
9
8
|
import fs from 'fs';
|
|
10
9
|
import path from 'path';
|
|
11
10
|
import crypto from 'crypto';
|
|
12
11
|
import { dedent } from './utils.js';
|
|
13
|
-
import { babelPluginJsxTransform, removeJsxExpressionContainer, } from './babel-jsx.js';
|
|
12
|
+
import { babelPluginJsxTransform, babelPluginSuppressHydration, removeJsxExpressionContainer, } from './babel-jsx.js';
|
|
14
13
|
import { babelPluginTypedoc } from './babel-typedoc.js';
|
|
15
|
-
import { breakpointsStyles, defaultBreakpointSizes, getFontsStyles, logFontsUsage, } from './css.js';
|
|
14
|
+
import { breakpointsStyles, defaultBreakpointSizes, getFontsStyles, logFontsUsage, } from './css-core.js';
|
|
16
15
|
import { propControlsToTypedocComments, componentImportedName, } from './typescript.js';
|
|
17
16
|
import { defaultExternalPackages, esbuildPluginBundleDependencies, resolveRedirect, } from './esbuild.js';
|
|
18
17
|
import { notifyError } from './sentry.js';
|
|
@@ -133,7 +132,6 @@ export async function bundle({ config, cwd: out = '', watch = false, signal = un
|
|
|
133
132
|
missingPackages.add(pkg);
|
|
134
133
|
},
|
|
135
134
|
}),
|
|
136
|
-
nodeModulesPolyfillPlugin({}),
|
|
137
135
|
{
|
|
138
136
|
name: 'virtual loader',
|
|
139
137
|
setup(build) {
|
|
@@ -370,6 +368,14 @@ export async function bundle({ config, cwd: out = '', watch = false, signal = un
|
|
|
370
368
|
typedocComments,
|
|
371
369
|
};
|
|
372
370
|
}
|
|
371
|
+
catch (e) {
|
|
372
|
+
const name = path
|
|
373
|
+
.relative(out, file.path)
|
|
374
|
+
.replace(/\.jsx?$/, '');
|
|
375
|
+
spinner.error(`Failed to extract types for ${name}: ${e instanceof Error ? e.message : e}`);
|
|
376
|
+
logger.log(e instanceof Error ? e.stack : e);
|
|
377
|
+
return undefined;
|
|
378
|
+
}
|
|
373
379
|
finally {
|
|
374
380
|
sema.release();
|
|
375
381
|
}
|
|
@@ -393,14 +399,21 @@ export async function bundle({ config, cwd: out = '', watch = false, signal = un
|
|
|
393
399
|
logFontsUsage(allFonts)
|
|
394
400
|
?.split('\n')
|
|
395
401
|
.forEach((x) => logger.log(x));
|
|
402
|
+
function isChunkPath(filePath) {
|
|
403
|
+
return (filePath.includes('/chunks/') ||
|
|
404
|
+
filePath.includes('\\chunks\\'));
|
|
405
|
+
}
|
|
396
406
|
const jsxFiles = buildResult.outputFiles
|
|
397
407
|
.filter((x) => x.path.endsWith('.js') &&
|
|
408
|
+
!isChunkPath(x.path) &&
|
|
398
409
|
fs.existsSync(getFilePaths(x.path, out).jsxPath))
|
|
399
410
|
.map((x) => getFilePaths(x.path, out).jsxPath);
|
|
400
411
|
const outFiles = buildResult.outputFiles
|
|
401
412
|
.map((x) => {
|
|
402
413
|
const paths = getFilePaths(x.path, out);
|
|
403
|
-
if (x.path.endsWith('.js') &&
|
|
414
|
+
if (x.path.endsWith('.js') &&
|
|
415
|
+
!isChunkPath(x.path) &&
|
|
416
|
+
fs.existsSync(paths.jsxPath)) {
|
|
404
417
|
return null; // Will be handled by jsx files
|
|
405
418
|
}
|
|
406
419
|
return paths.finalJsPath;
|
|
@@ -483,6 +496,7 @@ export async function bundle({ config, cwd: out = '', watch = false, signal = un
|
|
|
483
496
|
try {
|
|
484
497
|
const plugins = [
|
|
485
498
|
// babelPluginDeduplicateImports,
|
|
499
|
+
babelPluginSuppressHydration,
|
|
486
500
|
babelPluginJsxTransform,
|
|
487
501
|
removeJsxExpressionContainer,
|
|
488
502
|
];
|
|
@@ -521,9 +535,15 @@ export async function bundle({ config, cwd: out = '', watch = false, signal = un
|
|
|
521
535
|
}
|
|
522
536
|
}
|
|
523
537
|
catch (e) {
|
|
538
|
+
spinner.warn(`Babel/Biome formatting failed for ${componentName}: ${e instanceof Error ? e.message : e}`);
|
|
539
|
+
logger.log(e instanceof Error ? e.stack : e);
|
|
524
540
|
notifyError(e, 'babel transform and format');
|
|
525
541
|
}
|
|
526
542
|
}
|
|
543
|
+
else if (tooBig) {
|
|
544
|
+
const sizeMB = (file.text.length / (1024 * 1024)).toFixed(2);
|
|
545
|
+
spinner.warn(`Skipping JSX formatting for ${componentName} (${sizeMB} MB exceeds ${(tooBigSize / (1024 * 1024)).toFixed(2)} MB limit)`);
|
|
546
|
+
}
|
|
527
547
|
const prefix = `// @ts-nocheck\n` + `/* eslint-disable */\n` + doNotEditComment;
|
|
528
548
|
const codeJsx = prefix + formatted;
|
|
529
549
|
const codeJs = prefix + file.text;
|
|
@@ -533,7 +553,11 @@ export async function bundle({ config, cwd: out = '', watch = false, signal = un
|
|
|
533
553
|
});
|
|
534
554
|
// Always write the temp .js file for type extraction
|
|
535
555
|
await fs.promises.writeFile(paths.tempJsPath, codeJs, 'utf-8');
|
|
536
|
-
//
|
|
556
|
+
// Write .jsx file if formatting succeeded, or fall back to writing
|
|
557
|
+
// unformatted .js content into the .jsx path when formatting fails
|
|
558
|
+
// (babel error, component too big, etc.) but a stale .jsx already
|
|
559
|
+
// exists on disk. Without this fallback the stale .jsx keeps old
|
|
560
|
+
// chunk imports while the old chunks are deleted, breaking the build.
|
|
537
561
|
if (didFormat && codeJsx !== existing) {
|
|
538
562
|
await fs.promises.writeFile(paths.jsxPath, codeJsx, 'utf-8');
|
|
539
563
|
logger.log(`Updated JSX file for ${componentName}`);
|
|
@@ -541,6 +565,13 @@ export async function bundle({ config, cwd: out = '', watch = false, signal = un
|
|
|
541
565
|
else if (didFormat) {
|
|
542
566
|
logger.log(`JSX file unchanged for ${componentName}`);
|
|
543
567
|
}
|
|
568
|
+
else if (existing && codeJs !== existing) {
|
|
569
|
+
// Formatting failed but .jsx exists with stale content (e.g.
|
|
570
|
+
// old chunk hashes). Overwrite with unformatted JS so imports
|
|
571
|
+
// stay in sync with the current build's chunks.
|
|
572
|
+
await fs.promises.writeFile(paths.jsxPath, codeJs, 'utf-8');
|
|
573
|
+
logger.log(`Updated JSX file (unformatted) for ${componentName}`);
|
|
574
|
+
}
|
|
544
575
|
}
|
|
545
576
|
spinner.stop();
|
|
546
577
|
// await fs.promises.writeFile(
|
|
@@ -552,8 +583,10 @@ export async function bundle({ config, cwd: out = '', watch = false, signal = un
|
|
|
552
583
|
for (let file of buildResult.outputFiles) {
|
|
553
584
|
if (file.path.endsWith('.js')) {
|
|
554
585
|
const paths = getFilePaths(file.path, out);
|
|
555
|
-
if (
|
|
586
|
+
if (!isChunkPath(paths.tempJsPath) &&
|
|
587
|
+
fs.existsSync(paths.jsxPath)) {
|
|
556
588
|
// Remove temp .js file if .jsx equivalent exists
|
|
589
|
+
// (never applies to chunks which stay as .js)
|
|
557
590
|
logger.log('removing temp JS file with JSX equivalent:', path.relative(out, paths.tempJsPath));
|
|
558
591
|
try {
|
|
559
592
|
await fs.promises.rm(paths.tempJsPath);
|
|
@@ -713,16 +746,44 @@ export function getDarkModeSelector(opts) {
|
|
|
713
746
|
}
|
|
714
747
|
return '.dark {\n' + content + '\n' + '}';
|
|
715
748
|
}
|
|
749
|
+
// A CSS custom property value must not contain structural characters that would
|
|
750
|
+
// terminate the declaration or the surrounding `:root {}` block. Framer color
|
|
751
|
+
// styles can in rare cases carry malformed color strings (e.g. text scraped from
|
|
752
|
+
// a code-highlighting component), and an unescaped `}` closes the block early.
|
|
753
|
+
// The leaked text then becomes a top-level class rule like `.[-:=] { -: =; }`,
|
|
754
|
+
// which browsers tolerate but lightningcss (Vite's css minifier) rejects with
|
|
755
|
+
// "Expected identifier in class selector". Skip such tokens to keep styles.css
|
|
756
|
+
// always minifiable. See the getStyleTokensCss regression test.
|
|
757
|
+
function isSafeCssColorValue(value) {
|
|
758
|
+
if (typeof value !== 'string' || value === '') {
|
|
759
|
+
return false;
|
|
760
|
+
}
|
|
761
|
+
return !/[;{}\n\r]/.test(value);
|
|
762
|
+
}
|
|
716
763
|
export function getStyleTokensCss(tokens, darkModeType = 'class') {
|
|
717
764
|
if (!tokens?.length) {
|
|
718
765
|
return '';
|
|
719
766
|
}
|
|
767
|
+
// Drop tokens whose color values would produce invalid CSS. Both light and
|
|
768
|
+
// dark colors must be safe, otherwise the token is skipped entirely so the
|
|
769
|
+
// --unframer-* and --token-* variables never desync.
|
|
770
|
+
const validTokens = tokens.filter((token) => {
|
|
771
|
+
if (!isSafeCssColorValue(token.lightColor) ||
|
|
772
|
+
!isSafeCssColorValue(token.darkColor)) {
|
|
773
|
+
logger.log(`Skipping style token ${JSON.stringify(token.name || token.id)}: unsafe color value`);
|
|
774
|
+
return false;
|
|
775
|
+
}
|
|
776
|
+
return true;
|
|
777
|
+
});
|
|
778
|
+
if (!validTokens.length) {
|
|
779
|
+
return '';
|
|
780
|
+
}
|
|
720
781
|
// Deduplicate --unframer-* names: multiple Framer tokens can share the same
|
|
721
782
|
// user-facing name (e.g. two tokens both called "black" with different UUIDs).
|
|
722
783
|
// Keep only the first occurrence of each kebab-cased name to avoid silent
|
|
723
784
|
// CSS overwrites. The --token-{uuid} variables are always unique and unaffected.
|
|
724
785
|
const seenNames = new Set();
|
|
725
|
-
const deduplicatedTokens =
|
|
786
|
+
const deduplicatedTokens = validTokens.filter((token) => {
|
|
726
787
|
const name = kebabCase(token.name || token.id);
|
|
727
788
|
if (seenNames.has(name)) {
|
|
728
789
|
return false;
|
|
@@ -737,7 +798,7 @@ export function getStyleTokensCss(tokens, darkModeType = 'class') {
|
|
|
737
798
|
token.lightColor +
|
|
738
799
|
';')
|
|
739
800
|
.join('\n');
|
|
740
|
-
const lightTokens =
|
|
801
|
+
const lightTokens = validTokens
|
|
741
802
|
.map((token) => ' --token-' + token.id + ': ' + token.lightColor + ';')
|
|
742
803
|
.join('\n');
|
|
743
804
|
const darkUnframerTokens = deduplicatedTokens
|
|
@@ -747,7 +808,7 @@ export function getStyleTokensCss(tokens, darkModeType = 'class') {
|
|
|
747
808
|
token.darkColor +
|
|
748
809
|
';')
|
|
749
810
|
.join('\n');
|
|
750
|
-
const darkTokens =
|
|
811
|
+
const darkTokens = validTokens
|
|
751
812
|
.map((token) => ' --token-' + token.id + ': ' + token.darkColor + ';')
|
|
752
813
|
.join('\n');
|
|
753
814
|
return (':root {\n' +
|
|
@@ -819,7 +880,7 @@ export async function extractPropControlsUnsafe(filename, name) {
|
|
|
819
880
|
return {};
|
|
820
881
|
}
|
|
821
882
|
// console.log(stdout)
|
|
822
|
-
return safeJsonParse(stdout);
|
|
883
|
+
return safeJsonParse(stdout) || {};
|
|
823
884
|
}
|
|
824
885
|
function safeJsonParse(text) {
|
|
825
886
|
try {
|