@zseven-w/openpencil 0.7.2 → 0.7.4
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/openpencil-cli.cjs +176 -16
- package/dist/openpencil-cli.cjs.map +2 -2
- package/package.json +3 -3
package/dist/openpencil-cli.cjs
CHANGED
|
@@ -2156,7 +2156,7 @@ This context will guide the subtask decomposition and style guide selection.`
|
|
|
2156
2156
|
"budget": 500,
|
|
2157
2157
|
"category": "base"
|
|
2158
2158
|
},
|
|
2159
|
-
"content": 'OVERFLOW PREVENTION (CRITICAL):\n\n- Text in vertical layout: width="fill_container" + textGrowth="fixed-width". In horizontal: width="fit_content".\n- NEVER set fixed pixel width on text inside layout frames (e.g. width:378 in 195px card - overflows!).\n- Fixed-width children must be <= parent content area (parent width - padding).\n- Badges: short labels only (CJK <=8 chars / Latin <=16 chars).'
|
|
2159
|
+
"content": 'OVERFLOW PREVENTION (CRITICAL):\n\n- Text in vertical layout: width="fill_container" + textGrowth="fixed-width". In horizontal: width="fit_content".\n- NEVER set fixed pixel width on text inside layout frames (e.g. width:378 in 195px card - overflows!).\n- Fixed-width children must be <= parent content area (parent width - padding).\n- Badges: short labels only (CJK <=8 chars / Latin <=16 chars).\n\n## HORIZONTAL SCROLL ROWS (cards / chips / categories)\n\nWhen the spec says "horizontal scrolling cards", "swipeable row", "chip row", or similar, generate EXACTLY this structure \u2014 do NOT just emit 6 cards inside a horizontal layout, the children will spill outside the page frame.\n\nStructure:\n\n- A wrapper frame with `width="fill_container"`, `height="fit_content"`, `layout="vertical"`, `clipContent=true`.\n- Inside it, a row frame with `width="fit_content"`, `height="fit_content"`, `layout="horizontal"`, `gap=12`, `padding=[0,20]`.\n- The row frame holds the actual cards.\n\nEvery card in the row MUST:\n\n- Have a FIXED numeric `width` (typically 120-160 for mobile, 200-260 for desktop). Never `fill_container`, never `fit_content` - fixed pixels.\n- Share identical width with its siblings for visual rhythm.\n\nExample - 6 workout cards inside a 375px-wide mobile page:\n\n```json\n{\n "id": "cards-scroll",\n "type": "frame",\n "name": "Workouts Scroll",\n "width": "fill_container",\n "height": "fit_content",\n "layout": "vertical",\n "clipContent": true,\n "children": [\n {\n "id": "cards-row",\n "type": "frame",\n "name": "Workouts Row",\n "width": "fit_content",\n "height": "fit_content",\n "layout": "horizontal",\n "gap": 12,\n "padding": [0, 20],\n "children": [\n {\n "id": "card-hiit",\n "type": "frame",\n "width": 140,\n "height": 160,\n "cornerRadius": 20,\n "layout": "vertical",\n "gap": 8,\n "padding": 16,\n "fill": [{ "type": "solid", "color": "#1a1a1a" }],\n "children": []\n },\n {\n "id": "card-strength",\n "type": "frame",\n "width": 140,\n "height": 160,\n "cornerRadius": 20,\n "layout": "vertical",\n "gap": 8,\n "padding": 16,\n "fill": [{ "type": "solid", "color": "#1a1a1a" }],\n "children": []\n }\n ]\n }\n ]\n}\n```\n\nAnti-patterns (do NOT emit any of these):\n\n- Putting 5+ cards directly inside a `layout="horizontal"` page-root frame (they overflow the phone width).\n- Using `fill_container` on cards in a horizontal row (they squish down to invisibility).\n- Using `width="fit_content"` on cards - text-driven widths are unpredictable and break rhythm.\n- Skipping the `clipContent=true` wrapper and relying on Skia to clip (it doesn\'t \u2014 only `clipContent:true` enables clipping).'
|
|
2160
2160
|
},
|
|
2161
2161
|
{
|
|
2162
2162
|
"meta": {
|
|
@@ -2339,14 +2339,19 @@ This context will guide the subtask decomposition and style guide selection.`
|
|
|
2339
2339
|
"name": "incremental-add",
|
|
2340
2340
|
"description": "Rules for adding new elements to existing designs",
|
|
2341
2341
|
"phase": [
|
|
2342
|
-
"maintenance"
|
|
2342
|
+
"maintenance",
|
|
2343
|
+
"generation"
|
|
2343
2344
|
],
|
|
2344
2345
|
"trigger": {
|
|
2345
2346
|
"keywords": [
|
|
2346
2347
|
"add",
|
|
2347
2348
|
"insert",
|
|
2348
2349
|
"new section",
|
|
2349
|
-
"append"
|
|
2350
|
+
"append",
|
|
2351
|
+
"continue",
|
|
2352
|
+
"\u7EE7\u7EED",
|
|
2353
|
+
"\u518D\u52A0",
|
|
2354
|
+
"\u8FFD\u52A0"
|
|
2350
2355
|
]
|
|
2351
2356
|
},
|
|
2352
2357
|
"priority": 20,
|
|
@@ -2668,7 +2673,7 @@ Your output must remain valid JSON/JSONL only.`
|
|
|
2668
2673
|
"budget": 2e3,
|
|
2669
2674
|
"category": "knowledge"
|
|
2670
2675
|
},
|
|
2671
|
-
"content":
|
|
2676
|
+
"content": "SEMANTIC ROLES (add \"role\" to nodes \u2014 system fills unset props based on role):\n\nLayout roles:\n\n- section: layout=vertical, width=fill_container, height=fit_content, gap=24, padding=[60,80] (mobile: [40,16]), alignItems=center\n- row: layout=horizontal, width=fill_container, gap=16, alignItems=center\n- column: layout=vertical, width=fill_container, gap=16\n- centered-content: layout=vertical, width=1080 (mobile: fill_container), gap=24, alignItems=center\n- form-group: layout=vertical, width=fill_container, gap=16\n- divider: width=fill_container, height=1, layout=none (vertical divider: width=1, height=fill_container)\n- spacer: width=fill_container, height=40\n\nNavigation roles:\n\n- navbar: layout=horizontal, width=fill_container, height=72 (mobile: 56), padding=[0,80] (mobile: [0,16]), alignItems=center, justifyContent=space_between\n- nav-links: layout=horizontal, gap=24, alignItems=center\n- nav-link: textGrowth=auto, lineHeight=1.2\n\nInteractive roles:\n\n- button: padding=[12,24], height=44, layout=horizontal, gap=8, alignItems=center, justifyContent=center, cornerRadius=8. In navbar: padding=[8,16], height=36. In form-group: width=fill_container, height=48, cornerRadius=10\n- icon-button: width=44, height=44, layout=horizontal, justifyContent=center, alignItems=center, cornerRadius=8\n- badge: layout=horizontal, padding=[6,12], gap=4, alignItems=center, justifyContent=center, cornerRadius=999\n- tag: layout=horizontal, padding=[4,10], gap=4, alignItems=center, justifyContent=center, cornerRadius=6\n- pill: layout=horizontal, padding=[6,14], gap=6, alignItems=center, justifyContent=center, cornerRadius=999\n- input: height=48, layout=horizontal, padding=[12,16], alignItems=center, cornerRadius=8. In vertical layout: width=fill_container\n- form-input: width=fill_container, height=48, layout=horizontal, padding=[12,16], alignItems=center, cornerRadius=8\n- search-bar: layout=horizontal, height=44, padding=[10,16], gap=8, alignItems=center, cornerRadius=22\n\nDisplay roles:\n\n- card: layout=vertical, gap=12, cornerRadius=12, clipContent=true. In horizontal layout: width=fill_container, height=fill_container\n- stat-card: layout=vertical, gap=8, padding=[24,24], cornerRadius=12. In horizontal layout: width=fill_container, height=fill_container\n- pricing-card: layout=vertical, gap=16, padding=[32,24], cornerRadius=16, clipContent=true. In horizontal layout: width=fill_container, height=fill_container\n- image-card: layout=vertical, gap=0, cornerRadius=12, clipContent=true\n- feature-card: layout=vertical, gap=12, padding=[24,24], cornerRadius=12. In horizontal layout: width=fill_container, height=fill_container\n\nMedia roles:\n\n- phone-mockup: width=280, height=560, cornerRadius=32, layout=none\n- screenshot-frame: cornerRadius=12, clipContent=true\n- avatar: width/height=48, cornerRadius=24, clipContent=true (size adapts to explicit width)\n- icon: width=24, height=24\n\nLayout-escape roles:\n\n- overlay: the ONLY way to place a child at absolute x/y inside a parent that uses `layout: vertical|horizontal`. Use for notification dots on an icon, corner ribbons on a card, floating status indicators. The child keeps its explicit `x`/`y` while siblings flow normally. Do NOT use `role: 'overlay'` for inline components \u2014 `badge`, `pill`, `tag` are inline (they flow in layout like any other child, NOT floating). Do NOT use `role: 'overlay'` as a substitute for `layout: 'none'` on the parent.\n\nTypography roles:\n\n- heading: lineHeight=1.2 (CJK: 1.35), letterSpacing=-0.5 (CJK: 0). In vertical layout: textGrowth=fixed-width, width=fill_container\n- subheading: lineHeight=1.3 (CJK: 1.4), textGrowth=fixed-width, width=fill_container\n- body-text: lineHeight=1.5 (CJK: 1.6), textGrowth=fixed-width, width=fill_container\n- caption: lineHeight=1.3 (CJK: 1.4), textGrowth=auto\n- label: lineHeight=1.2, textGrowth=auto, textAlignVertical=middle\n\nContent roles:\n\n- hero: layout=vertical, width=fill_container, height=fit_content, padding=[80,80] (mobile: [40,16]), gap=24, alignItems=center\n- feature-grid: layout=horizontal, width=fill_container, gap=24, alignItems=start\n- testimonial: layout=vertical, gap=16, padding=[24,24], cornerRadius=12\n- cta-section: layout=vertical, width=fill_container, height=fit_content, padding=[60,80] (mobile: [40,16]), gap=20, alignItems=center\n- footer: layout=vertical, width=fill_container, height=fit_content, padding=[48,80] (mobile: [32,16]), gap=24\n- stats-section: layout=horizontal, width=fill_container, height=fit_content, padding=[48,80] (mobile: [32,16]), gap=32, justifyContent=center, alignItems=center\n\nTable roles:\n\n- table: layout=vertical, width=fill_container, gap=0, clipContent=true\n- table-row: layout=horizontal, width=fill_container, alignItems=center, padding=[12,16]\n- table-header: layout=horizontal, width=fill_container, alignItems=center, padding=[12,16]\n- table-cell: width=fill_container\n\nYour explicit props ALWAYS override role defaults. Only unset properties get filled in."
|
|
2672
2677
|
},
|
|
2673
2678
|
{
|
|
2674
2679
|
"meta": {
|
|
@@ -4723,7 +4728,7 @@ async function handleSetVariables(params) {
|
|
|
4723
4728
|
if (params.replace) {
|
|
4724
4729
|
doc.variables = params.variables;
|
|
4725
4730
|
} else {
|
|
4726
|
-
doc.variables = { ...doc.variables
|
|
4731
|
+
doc.variables = { ...doc.variables, ...params.variables };
|
|
4727
4732
|
}
|
|
4728
4733
|
await saveDocument(filePath, doc);
|
|
4729
4734
|
return { variables: doc.variables };
|
|
@@ -4734,7 +4739,7 @@ async function handleSetThemes(params) {
|
|
|
4734
4739
|
if (params.replace) {
|
|
4735
4740
|
doc.themes = params.themes;
|
|
4736
4741
|
} else {
|
|
4737
|
-
doc.themes = { ...doc.themes
|
|
4742
|
+
doc.themes = { ...doc.themes, ...params.themes };
|
|
4738
4743
|
}
|
|
4739
4744
|
await saveDocument(filePath, doc);
|
|
4740
4745
|
return { themes: doc.themes };
|
|
@@ -5042,11 +5047,18 @@ var init_font_manager = __esm({
|
|
|
5042
5047
|
systemFontFamilies = /* @__PURE__ */ new Set();
|
|
5043
5048
|
/** In-flight font fetch promises to avoid duplicate requests */
|
|
5044
5049
|
pendingFetches = /* @__PURE__ */ new Map();
|
|
5050
|
+
/** Cached set of native (OS-installed) font families from Local Font Access API (lowercase) */
|
|
5051
|
+
nativeFontSet = null;
|
|
5052
|
+
/** Full native font entries with blob accessors, keyed by lowercase family name */
|
|
5053
|
+
nativeFontMap = /* @__PURE__ */ new Map();
|
|
5054
|
+
/** Current permission state for native font access (Local Font Access API) */
|
|
5055
|
+
nativeFontPermission = "prompt";
|
|
5045
5056
|
constructor(ck, options) {
|
|
5046
5057
|
this.provider = ck.TypefaceFontProvider.Make();
|
|
5047
5058
|
this.fontBasePath = options?.fontBasePath ?? "/fonts/";
|
|
5048
5059
|
if (!this.fontBasePath.endsWith("/")) this.fontBasePath += "/";
|
|
5049
5060
|
this.googleFontsCssUrl = options?.googleFontsCssUrl ?? "https://fonts.googleapis.com/css2";
|
|
5061
|
+
this._checkPermissionState();
|
|
5050
5062
|
}
|
|
5051
5063
|
getProvider() {
|
|
5052
5064
|
return this.provider;
|
|
@@ -5118,7 +5130,8 @@ var init_font_manager = __esm({
|
|
|
5118
5130
|
}
|
|
5119
5131
|
}
|
|
5120
5132
|
/**
|
|
5121
|
-
* Ensure a font family is loaded. Tries bundled fonts first, then
|
|
5133
|
+
* Ensure a font family is loaded. Tries bundled fonts first, then native
|
|
5134
|
+
* fonts (Local Font Access API + canvas heuristic), then Google Fonts CDN.
|
|
5122
5135
|
*/
|
|
5123
5136
|
async ensureFont(family, weights = [400, 500, 600, 700]) {
|
|
5124
5137
|
const key = family.toLowerCase();
|
|
@@ -5133,6 +5146,7 @@ var init_font_manager = __esm({
|
|
|
5133
5146
|
this.pendingFetches.delete(key);
|
|
5134
5147
|
if (!result) {
|
|
5135
5148
|
if (isSystemFont(family)) {
|
|
5149
|
+
console.warn(`[FontManager] "${family}" is now a system font fallback after failed load.`);
|
|
5136
5150
|
this.systemFontFamilies.add(key);
|
|
5137
5151
|
} else {
|
|
5138
5152
|
this.failedFamilies.add(key);
|
|
@@ -5152,6 +5166,91 @@ var init_font_manager = __esm({
|
|
|
5152
5166
|
});
|
|
5153
5167
|
return loaded;
|
|
5154
5168
|
}
|
|
5169
|
+
/**
|
|
5170
|
+
* Request native font access from the user via the Local Font Access API.
|
|
5171
|
+
* Must be called from a user gesture context (click handler) for the
|
|
5172
|
+
* browser to show the permission prompt.
|
|
5173
|
+
*
|
|
5174
|
+
* Returns true if access was granted and fonts were enumerated.
|
|
5175
|
+
*/
|
|
5176
|
+
async requestNativeFontAccess() {
|
|
5177
|
+
if (typeof window === "undefined") {
|
|
5178
|
+
this.nativeFontPermission = "unavailable";
|
|
5179
|
+
return false;
|
|
5180
|
+
}
|
|
5181
|
+
if (!("queryLocalFonts" in window)) {
|
|
5182
|
+
console.warn("[FontManager] Local Font Access API not available in this browser.");
|
|
5183
|
+
this.nativeFontPermission = "unavailable";
|
|
5184
|
+
return false;
|
|
5185
|
+
}
|
|
5186
|
+
try {
|
|
5187
|
+
const fonts = await window.queryLocalFonts();
|
|
5188
|
+
const families = /* @__PURE__ */ new Set();
|
|
5189
|
+
this.nativeFontMap.clear();
|
|
5190
|
+
for (const f of fonts) {
|
|
5191
|
+
const key = f.family.toLowerCase();
|
|
5192
|
+
families.add(key);
|
|
5193
|
+
const entry = {
|
|
5194
|
+
family: f.family,
|
|
5195
|
+
fullName: f.fullName,
|
|
5196
|
+
postscriptName: f.postscriptName,
|
|
5197
|
+
style: f.style,
|
|
5198
|
+
blob: f.blob.bind(f)
|
|
5199
|
+
};
|
|
5200
|
+
const existing = this.nativeFontMap.get(key) ?? [];
|
|
5201
|
+
existing.push(entry);
|
|
5202
|
+
this.nativeFontMap.set(key, existing);
|
|
5203
|
+
}
|
|
5204
|
+
this.nativeFontSet = families;
|
|
5205
|
+
this.nativeFontPermission = "granted";
|
|
5206
|
+
console.log(`[FontManager] Native font access granted \u2014 ${families.size} families found.`);
|
|
5207
|
+
return true;
|
|
5208
|
+
} catch (e) {
|
|
5209
|
+
const errMsg = e instanceof Error ? e.message : String(e);
|
|
5210
|
+
if (e instanceof DOMException && e.name === "NotAllowedError") {
|
|
5211
|
+
try {
|
|
5212
|
+
const status = await navigator.permissions.query({
|
|
5213
|
+
name: "local-fonts"
|
|
5214
|
+
});
|
|
5215
|
+
if (status.state === "prompt") {
|
|
5216
|
+
console.warn(
|
|
5217
|
+
"[FontManager] Native font access not yet prompted \u2014 will retry on next user gesture."
|
|
5218
|
+
);
|
|
5219
|
+
this.nativeFontPermission = "prompt";
|
|
5220
|
+
this.nativeFontSet = null;
|
|
5221
|
+
return false;
|
|
5222
|
+
}
|
|
5223
|
+
} catch {
|
|
5224
|
+
}
|
|
5225
|
+
console.warn("[FontManager] Native font access denied by user.");
|
|
5226
|
+
this.nativeFontPermission = "denied";
|
|
5227
|
+
} else {
|
|
5228
|
+
console.warn("[FontManager] Native font access failed:", errMsg);
|
|
5229
|
+
this.nativeFontPermission = "denied";
|
|
5230
|
+
}
|
|
5231
|
+
this.nativeFontSet = /* @__PURE__ */ new Set();
|
|
5232
|
+
return false;
|
|
5233
|
+
}
|
|
5234
|
+
}
|
|
5235
|
+
/**
|
|
5236
|
+
* Check the current permission state without triggering a prompt.
|
|
5237
|
+
*/
|
|
5238
|
+
async _checkPermissionState() {
|
|
5239
|
+
if (typeof navigator === "undefined" || !navigator.permissions) {
|
|
5240
|
+
return;
|
|
5241
|
+
}
|
|
5242
|
+
try {
|
|
5243
|
+
const result = await navigator.permissions.query({
|
|
5244
|
+
name: "local-fonts"
|
|
5245
|
+
});
|
|
5246
|
+
this.nativeFontPermission = result.state;
|
|
5247
|
+
if (result.state === "granted") {
|
|
5248
|
+
this.requestNativeFontAccess().catch(() => {
|
|
5249
|
+
});
|
|
5250
|
+
}
|
|
5251
|
+
} catch {
|
|
5252
|
+
}
|
|
5253
|
+
}
|
|
5155
5254
|
async _loadFont(family, weights) {
|
|
5156
5255
|
const bundled = BUNDLED_FONTS[family.toLowerCase()];
|
|
5157
5256
|
if (bundled) {
|
|
@@ -5159,10 +5258,56 @@ var init_font_manager = __esm({
|
|
|
5159
5258
|
const ok = await this._fetchLocalFonts(family, urls, bundled);
|
|
5160
5259
|
if (ok) return true;
|
|
5161
5260
|
}
|
|
5162
|
-
if (
|
|
5261
|
+
if (isKnownNonGoogleFont(family)) {
|
|
5163
5262
|
return false;
|
|
5164
5263
|
}
|
|
5165
|
-
|
|
5264
|
+
const nativeLoaded = await this._loadNativeFontData(family);
|
|
5265
|
+
if (nativeLoaded) return true;
|
|
5266
|
+
const nativeFonts = await this.getNativeFontSet();
|
|
5267
|
+
if (nativeFonts.has(family.toLowerCase())) {
|
|
5268
|
+
const blobLoaded = await this._loadNativeFontData(family);
|
|
5269
|
+
if (blobLoaded) return true;
|
|
5270
|
+
this.systemFontFamilies.add(family.toLowerCase());
|
|
5271
|
+
return false;
|
|
5272
|
+
}
|
|
5273
|
+
if (isFontLocallyAvailable(family)) {
|
|
5274
|
+
this.systemFontFamilies.add(family.toLowerCase());
|
|
5275
|
+
return false;
|
|
5276
|
+
}
|
|
5277
|
+
const isFontFromGoogle = await this._fetchGoogleFont(family, weights);
|
|
5278
|
+
if (isFontFromGoogle) return true;
|
|
5279
|
+
return false;
|
|
5280
|
+
}
|
|
5281
|
+
/**
|
|
5282
|
+
* Attempt to load a native font from the Local Font Access API blob data
|
|
5283
|
+
* into CanvasKit's TypefaceFontProvider for vector rendering.
|
|
5284
|
+
*/
|
|
5285
|
+
async _loadNativeFontData(family) {
|
|
5286
|
+
const key = family.toLowerCase();
|
|
5287
|
+
const entries = this.nativeFontMap.get(key);
|
|
5288
|
+
if (!entries || entries.length === 0) return false;
|
|
5289
|
+
let registered = 0;
|
|
5290
|
+
for (const entry of entries) {
|
|
5291
|
+
try {
|
|
5292
|
+
const blob = await entry.blob();
|
|
5293
|
+
const buffer = await blob.arrayBuffer();
|
|
5294
|
+
if (buffer.byteLength > 0 && this.registerFont(buffer, family)) {
|
|
5295
|
+
registered++;
|
|
5296
|
+
}
|
|
5297
|
+
} catch (e) {
|
|
5298
|
+
console.warn(
|
|
5299
|
+
`[FontManager] Failed to load native font blob for "${entry.fullName}":`,
|
|
5300
|
+
e instanceof Error ? e.message : String(e)
|
|
5301
|
+
);
|
|
5302
|
+
}
|
|
5303
|
+
}
|
|
5304
|
+
if (registered > 0) {
|
|
5305
|
+
console.log(
|
|
5306
|
+
`[FontManager] Loaded "${family}" from native fonts (${registered}/${entries.length} variants).`
|
|
5307
|
+
);
|
|
5308
|
+
return true;
|
|
5309
|
+
}
|
|
5310
|
+
return false;
|
|
5166
5311
|
}
|
|
5167
5312
|
async _fetchLocalFonts(family, urls, relPaths) {
|
|
5168
5313
|
try {
|
|
@@ -5217,8 +5362,8 @@ var init_font_manager = __esm({
|
|
|
5217
5362
|
const fontBuffers = await Promise.all(
|
|
5218
5363
|
urls.map(async (url) => {
|
|
5219
5364
|
try {
|
|
5220
|
-
const resp =
|
|
5221
|
-
return resp.ok ? resp.arrayBuffer() : null;
|
|
5365
|
+
const resp = fetchWithTimeout(url, 8e3);
|
|
5366
|
+
return (await resp).ok ? (await resp).arrayBuffer() : null;
|
|
5222
5367
|
} catch {
|
|
5223
5368
|
return null;
|
|
5224
5369
|
}
|
|
@@ -5234,12 +5379,27 @@ var init_font_manager = __esm({
|
|
|
5234
5379
|
}
|
|
5235
5380
|
return false;
|
|
5236
5381
|
}
|
|
5382
|
+
/**
|
|
5383
|
+
* Build a set of all native (OS-installed) font families using the
|
|
5384
|
+
* Local Font Access API (Chrome 103+, Edge 103+).
|
|
5385
|
+
* Falls back to empty set if API is unavailable or permission denied.
|
|
5386
|
+
* Results are cached after the first successful call.
|
|
5387
|
+
*/
|
|
5388
|
+
async getNativeFontSet() {
|
|
5389
|
+
if (this.nativeFontSet) return this.nativeFontSet;
|
|
5390
|
+
if (this.nativeFontPermission !== "denied" && this.nativeFontPermission !== "unavailable") {
|
|
5391
|
+
await this.requestNativeFontAccess();
|
|
5392
|
+
}
|
|
5393
|
+
return this.nativeFontSet ?? /* @__PURE__ */ new Set();
|
|
5394
|
+
}
|
|
5237
5395
|
dispose() {
|
|
5238
5396
|
this.provider.delete();
|
|
5239
5397
|
this.loadedFamilies.clear();
|
|
5240
5398
|
this.failedFamilies.clear();
|
|
5241
5399
|
this.systemFontFamilies.clear();
|
|
5242
5400
|
this.pendingFetches.clear();
|
|
5401
|
+
this.nativeFontSet = null;
|
|
5402
|
+
this.nativeFontMap.clear();
|
|
5243
5403
|
}
|
|
5244
5404
|
};
|
|
5245
5405
|
localFontCache = /* @__PURE__ */ new Map();
|
|
@@ -6776,8 +6936,8 @@ async function handleLoadThemePreset(params) {
|
|
|
6776
6936
|
if (data.type !== "openpencil-theme-preset") {
|
|
6777
6937
|
throw new Error("Invalid theme preset file");
|
|
6778
6938
|
}
|
|
6779
|
-
doc.themes = { ...doc.themes
|
|
6780
|
-
doc.variables = { ...doc.variables
|
|
6939
|
+
doc.themes = { ...doc.themes, ...data.themes };
|
|
6940
|
+
doc.variables = { ...doc.variables, ...data.variables };
|
|
6781
6941
|
await saveDocument(filePath, doc);
|
|
6782
6942
|
return {
|
|
6783
6943
|
themes: doc.themes,
|
|
@@ -13775,7 +13935,7 @@ init_define_import_meta_env();
|
|
|
13775
13935
|
// apps/cli/package.json
|
|
13776
13936
|
var package_default = {
|
|
13777
13937
|
name: "@zseven-w/openpencil",
|
|
13778
|
-
version: "0.7.
|
|
13938
|
+
version: "0.7.4",
|
|
13779
13939
|
description: "CLI for OpenPencil \u2014 control the design tool from your terminal",
|
|
13780
13940
|
homepage: "https://github.com/ZSeven-W/openpencil/tree/main/apps/cli",
|
|
13781
13941
|
bugs: {
|
|
@@ -13802,8 +13962,8 @@ var package_default = {
|
|
|
13802
13962
|
compile: "cd ../.. && bun run cli:compile"
|
|
13803
13963
|
},
|
|
13804
13964
|
dependencies: {
|
|
13805
|
-
"@zseven-w/pen-figma": "0.7.
|
|
13806
|
-
"@zseven-w/pen-mcp": "0.7.
|
|
13965
|
+
"@zseven-w/pen-figma": "0.7.4",
|
|
13966
|
+
"@zseven-w/pen-mcp": "0.7.4"
|
|
13807
13967
|
}
|
|
13808
13968
|
};
|
|
13809
13969
|
|