@lightspeed/crane 3.1.0 → 3.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lightspeed/crane",
3
- "version": "3.1.0",
3
+ "version": "3.2.1",
4
4
  "type": "module",
5
5
  "bin": "bin/crane.js",
6
6
  "main": "./dist/app.mjs",
@@ -65,7 +65,7 @@
65
65
  },
66
66
  "dependencies": {
67
67
  "@jridgewell/sourcemap-codec": "^1.5.4",
68
- "@lightspeed/crane-api": "2.1.0",
68
+ "@lightspeed/crane-api": "2.2.1",
69
69
  "@lightspeed/eslint-config-crane": "1.1.3",
70
70
  "@types/micromatch": "^4.0.8",
71
71
  "@types/prompts": "^2.4.2",
@@ -435,7 +435,7 @@ async function handleGetBlockConfigFull(
435
435
  */
436
436
  function getAvailableShowcases(blockType: BlockType, blockName: string, distPath: string): string[] {
437
437
  try {
438
- const showcasesPath = path.join(distPath, blockType, blockName, 'js', 'showcases');
438
+ const showcasesPath = path.resolve(distPath, blockType, blockName, 'js', 'showcases');
439
439
 
440
440
  if (!fs.existsSync(showcasesPath)) {
441
441
  console.warn(`[API Routes] Showcases directory not found for ${blockType}/"${blockName}": ${showcasesPath}`);
@@ -239,11 +239,38 @@ export function mergeDesign(
239
239
  return result;
240
240
  }
241
241
 
242
+ function parseAccordionDesign(comp: any): Record<string, any> {
243
+ const items: Record<string, any> = {};
244
+ Object.entries(comp.items || {}).forEach(([itemName, item]: [string, any]) => {
245
+ const editors: Record<string, any> = {};
246
+ Object.entries(item.editors || {}).forEach(([editorName, editor]: [string, any]) => {
247
+ editors[editorName] = editor.defaults || {};
248
+ });
249
+ items[itemName] = { label: item.label, editors };
250
+ });
251
+ return { sortable: comp.sortable, items };
252
+ }
253
+
254
+ function mergeAccordionShowcase(baseAccordion: Record<string, any>, showcaseAccordion: Record<string, any>): Record<string, any> {
255
+ const mergedItems: Record<string, any> = { ...baseAccordion.items };
256
+ Object.entries(showcaseAccordion.items || {}).forEach(([itemName, showcaseItem]: [string, any]) => {
257
+ const baseItem = mergedItems[itemName];
258
+ if (!baseItem) return;
259
+ mergedItems[itemName] = {
260
+ ...baseItem,
261
+ editors: { ...baseItem.editors, ...(showcaseItem.editors || {}) },
262
+ };
263
+ });
264
+ return { sortable: baseAccordion.sortable, items: mergedItems };
265
+ }
266
+
242
267
  export function designTransformer(design: Record<string, any>, showCaseDesign: Record<string, any>, isApiRender: boolean = false): Record<string, any> {
243
268
  const parsedDesign: Record<string, any> = {};
244
269
  const parsedShowcaseDesign: Record<string, any> = {};
270
+ const accordionKeys: Set<string> = new Set();
271
+
245
272
  Object.entries(design || {}).forEach(([key, comp]) => {
246
- // Skip DIVIDER and INFO elements - they're UI-only and don't have runtime data
273
+ // Skip DIVIDER elements - they're UI-only and don't have runtime data
247
274
  if (comp?.type === 'DIVIDER' || comp?.type === 'INFO') {
248
275
  return;
249
276
  }
@@ -251,15 +278,23 @@ export function designTransformer(design: Record<string, any>, showCaseDesign: R
251
278
  if (comp?.type === 'BACKGROUND') {
252
279
  return;
253
280
  }
254
- // Use defaults if available, otherwise use empty object
281
+ if (comp?.type === 'ACCORDION') {
282
+ accordionKeys.add(key);
283
+ parsedDesign[key] = parseAccordionDesign(comp);
284
+ return;
285
+ }
255
286
  parsedDesign[key] = comp?.defaults || {};
256
287
  });
257
288
 
258
289
  Object.entries(showCaseDesign || {}).forEach(([key, comp]) => {
259
- // Skip DIVIDER and INFO elements - they're UI-only and don't have runtime data
290
+ // Skip DIVIDER elements - they're UI-only and don't have runtime data
260
291
  if (comp?.type === 'DIVIDER' || comp?.type === 'INFO') {
261
292
  return;
262
293
  }
294
+ if (comp?.type === 'ACCORDION') {
295
+ parsedShowcaseDesign[key] = comp;
296
+ return;
297
+ }
263
298
  // Skip BACKGROUND - it's handled separately by createBackgroundDesign
264
299
  if (comp?.type === 'BACKGROUND') {
265
300
  return;
@@ -268,7 +303,24 @@ export function designTransformer(design: Record<string, any>, showCaseDesign: R
268
303
  parsedShowcaseDesign[key] = type == 'TEXT' ? { ...withoutType, visible: true } : withoutType;
269
304
  });
270
305
 
271
- let overridenDesign = mergeDesign(parsedDesign, parsedShowcaseDesign);
306
+ // Merge non-ACCORDION entries via shallow merge, then handle ACCORDION separately
307
+ const nonAccordionDesign: Record<string, any> = {};
308
+ const nonAccordionShowcase: Record<string, any> = {};
309
+ Object.entries(parsedDesign).forEach(([k, v]) => {
310
+ if (!accordionKeys.has(k)) nonAccordionDesign[k] = v;
311
+ });
312
+ Object.entries(parsedShowcaseDesign).forEach(([k, v]) => {
313
+ if (!accordionKeys.has(k)) nonAccordionShowcase[k] = v;
314
+ });
315
+
316
+ let overridenDesign = mergeDesign(nonAccordionDesign, nonAccordionShowcase);
317
+
318
+ accordionKeys.forEach(key => {
319
+ const showcase = parsedShowcaseDesign[key];
320
+ overridenDesign[key] = showcase
321
+ ? mergeAccordionShowcase(parsedDesign[key], showcase)
322
+ : parsedDesign[key];
323
+ });
272
324
 
273
325
  try {
274
326
  overridenDesign = updateHexColors(overridenDesign);
@@ -1,6 +1,7 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
2
  import * as fs from 'fs';
3
3
  import * as path from 'path';
4
+ import * as urlFromNode from 'url';
4
5
 
5
6
  import { getShowcaseState, BlockType, BLOCK_TYPES } from './preview';
6
7
 
@@ -50,7 +51,11 @@ function addCacheBust(url: string): string {
50
51
  * Note: server.js modules are NOT loaded here - they are rendered via renderServerModule
51
52
  */
52
53
  export async function loadModule(modulePath: string): Promise<unknown> {
53
- return import(/* @vite-ignore */ addCacheBust(modulePath));
54
+ const isWindows = typeof process !== 'undefined' && process.platform === 'win32';
55
+ const importPath = isWindows && path.isAbsolute(modulePath)
56
+ ? urlFromNode.pathToFileURL(modulePath).href
57
+ : modulePath;
58
+ return import(/* @vite-ignore */ addCacheBust(importPath));
54
59
  }
55
60
 
56
61
  /**