@lightspeed/crane 3.2.1 → 3.3.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lightspeed/crane",
3
- "version": "3.2.1",
3
+ "version": "3.3.0",
4
4
  "type": "module",
5
5
  "bin": "bin/crane.js",
6
6
  "main": "./dist/app.mjs",
@@ -58,41 +58,39 @@
58
58
  "mock-fs": "^5.5.0",
59
59
  "ts-jest": "^29.4.0",
60
60
  "ts-node": "^10.9.2",
61
- "typescript": "5.9.2",
61
+ "typescript": "5.9.3",
62
62
  "unbuild": "^3.5.0",
63
63
  "vite-plugin-dts": "^4.5.4",
64
64
  "vite-plugin-static-copy": "^3.1.0"
65
65
  },
66
66
  "dependencies": {
67
67
  "@jridgewell/sourcemap-codec": "^1.5.4",
68
- "@lightspeed/crane-api": "2.2.1",
68
+ "@lightspeed/crane-api": "2.3.0",
69
69
  "@lightspeed/eslint-config-crane": "1.1.3",
70
70
  "@types/micromatch": "^4.0.8",
71
71
  "@types/prompts": "^2.4.2",
72
72
  "@types/ws": "^8.5.3",
73
73
  "@vitejs/plugin-vue": "^6.0.1",
74
74
  "adm-zip": "^0.5.16",
75
- "ajv": "^8.17.1",
76
- "ajv-formats": "^3.0.1",
77
- "axios": "^1.11.0",
75
+ "axios": "^1.14.0",
78
76
  "axios-concurrency": "^1.0.4",
79
77
  "cac": "^6.7.14",
80
78
  "cli-progress": "^3.12.0",
81
79
  "eslint": "^9.33.0",
82
80
  "fs-extra": "^11.3.1",
83
- "glob": "^11.1.0",
84
- "jsonpath-plus": "^10.3.0",
81
+ "glob": "^13.0.6",
82
+ "jsonpath-plus": "^10.4.0",
85
83
  "kolorist": "^1.8.0",
86
84
  "prompts": "^2.4.2",
87
85
  "semver": "^7.7.2",
88
86
  "terser": "^5.44.0",
89
87
  "tinycolor2": "^1.6.0",
90
- "typescript": "5.9.2",
88
+ "typescript": "5.9.3",
91
89
  "vite": "^7.1.4",
92
- "vite-plugin-checker": "^0.10.3",
90
+ "vite-plugin-checker": "^0.12.0",
93
91
  "vite-plugin-compression": "^0.5.1",
94
92
  "vite-plugin-externals": "^0.6.2",
95
- "vite-tsconfig-paths": "^5.1.4",
93
+ "vite-tsconfig-paths": "^6.1.1",
96
94
  "vue": "^3.5.21",
97
95
  "vue-tsc": "^3.0.6",
98
96
  "ws": "^8.19.0"
@@ -102,10 +100,10 @@
102
100
  },
103
101
  "overrides": {
104
102
  "axios-concurrency": {
105
- "axios": "1.11.0"
103
+ "axios": "1.14.0"
106
104
  },
107
105
  "magic-string": "0.30.10",
108
- "glob": "^11.1.0",
106
+ "glob": "^13.0.6",
109
107
  "stylus": "^0.64.0"
110
108
  }
111
109
  }
@@ -1,4 +1,6 @@
1
- export default {
1
+ import { collection, section } from '@lightspeed/crane-api';
2
+
3
+ export default collection.configuration({
2
4
  metadata: {
3
5
  name: 'Example Collection',
4
6
  description: 'Example Collection with custom sections, headers, and footers',
@@ -11,11 +13,10 @@ export default {
11
13
  },
12
14
  },
13
15
  sections: [
14
- {
15
- type: 'custom',
16
+ section.custom({
16
17
  id: 'example-section',
17
18
  showcase_id: '1',
18
19
  category: 'COLLECTIONS',
19
- },
20
+ }),
20
21
  ],
21
- };
22
+ });
@@ -0,0 +1 @@
1
+ export { default } from '@lightspeed/eslint-config-crane';
@@ -1,11 +1,26 @@
1
1
  <template>
2
- <div>
3
- <a :href="madeWith?.url" target="{{ madeWith?.target }}">
4
- <span>{{ madeWith?.poweredBy }} &nbsp;</span>
5
- <span>
6
- <img :src="madeWith?.icon" alt="cart" />
7
- </span>
8
- <span>{{ madeWith?.company }}</span>
2
+ <div v-if="madeWith">
3
+ <a :href="madeWith.url" :target="madeWith.target">
4
+ <template v-if="isV2">
5
+ <span>{{ madeWith.poweredBy }}</span>
6
+ <span
7
+ v-if="madeWith.iconSvg"
8
+ v-html="madeWith.iconSvg"
9
+ />
10
+ <img
11
+ v-else-if="madeWith.icon"
12
+ :src="madeWith.icon"
13
+ :alt="madeWith.poweredBy"
14
+ />
15
+ <span v-if="madeWith.company">{{ madeWith.company }}</span>
16
+ </template>
17
+ <template v-else>
18
+ <span>{{ madeWith.poweredBy }} &nbsp;</span>
19
+ <span>
20
+ <img :src="madeWith.icon" alt="cart" />
21
+ </span>
22
+ <span>{{ madeWith.company }}</span>
23
+ </template>
9
24
  </a>
10
25
  </div>
11
26
  </template>
@@ -16,7 +31,8 @@ import { Design } from '../type.ts';
16
31
 
17
32
  const baseProps = useVueBaseProps<unknown, Design>();
18
33
  const siteContent: SiteContent = baseProps.site?.value satisfies SiteContent;
19
- const madeWith = siteContent.madeWith;
34
+ const isV2 = !!siteContent.madeWithV2;
35
+ const madeWith = siteContent.madeWithV2 ?? siteContent.madeWith;
20
36
  </script>
21
37
 
22
38
  <style scoped>
@@ -0,0 +1,6 @@
1
+ import { createLayoutApp } from '@lightspeed/crane-api';
2
+
3
+ import Main from './Main.vue';
4
+ import { Content, Design } from './type.ts';
5
+
6
+ export default createLayoutApp<Content, Design>(Main);
@@ -0,0 +1,6 @@
1
+ import { createLayoutApp } from '@lightspeed/crane-api';
2
+
3
+ import Main from './Main.vue';
4
+ import { Content, Design } from './type.ts';
5
+
6
+ export default createLayoutApp<Content, Design>(Main);
@@ -0,0 +1 @@
1
+ export default {} as const;
@@ -0,0 +1,6 @@
1
+ import { createLayoutApp } from '@lightspeed/crane-api';
2
+
3
+ import Main from './Main.vue';
4
+ import { Content, Design } from './type.ts';
5
+
6
+ export default createLayoutApp<Content, Design>(Main);
@@ -0,0 +1 @@
1
+ export default {} as const;
@@ -21,7 +21,7 @@
21
21
  "node": ">=22"
22
22
  },
23
23
  "overrides": {
24
- "glob": "^11.1.0",
24
+ "glob": "^13.0.6",
25
25
  "stylus": "^0.64.0"
26
26
  }
27
27
  }
@@ -16,6 +16,9 @@ import { debugLog } from './logger';
16
16
  import { getShowcaseData, BlockType, BLOCK_TYPES } from './preview';
17
17
  import { fetchTiles, updateTilesSection, updateCustomContent, getBlockType } from './utils';
18
18
 
19
+ /** Maximum allowed nesting depth for DECK settings */
20
+ const MAX_DECK_DEPTH = 2;
21
+
19
22
  /**
20
23
  * AppBlock type definition for block-config response
21
24
  */
@@ -206,9 +209,14 @@ function processEditorExceptDeck(setting: ContentEditor, fieldName: string) {
206
209
  }
207
210
 
208
211
  /**
209
- * Process a DECK editor: transform cards.defaultCardContent.settings into editors array
212
+ * Process a DECK editor: transform cards.defaultCardContent.settings into editors array.
213
+ * Supports nested DECK up to MAX_DECK_DEPTH levels.
210
214
  */
211
- function processDeckEditor(editor: DeckContentEditor, fieldName: string): Record<string, unknown> {
215
+ function processDeckEditor(
216
+ editor: DeckContentEditor,
217
+ fieldName: string,
218
+ depth: number = 1,
219
+ ): Record<string, unknown> {
212
220
  const result: Record<string, unknown> = {
213
221
  field: fieldName,
214
222
  type: 'DECK_EDITOR',
@@ -228,8 +236,23 @@ function processDeckEditor(editor: DeckContentEditor, fieldName: string): Record
228
236
  // Create editors array from settings and add to defaultCard
229
237
  if (settings) {
230
238
  const editors: Record<string, unknown>[] = [];
231
- for (const [settingFieldName, settingEditor] of Object.entries(settings)) {
232
- const processedEditor: Record<string, unknown> = processEditorExceptDeck(settingEditor, settingFieldName);
239
+ for (const [settingFieldName, settingEditor] of Object.entries(settings) as [string, ContentEditor][]) {
240
+ let processedEditor: Record<string, unknown>;
241
+ // Recursively process nested DECK editors, enforcing MAX_DECK_DEPTH
242
+ if (settingEditor.type === 'DECK') {
243
+ if (depth >= MAX_DECK_DEPTH) {
244
+ throw new Error(
245
+ `Maximum DECK nesting depth of ${MAX_DECK_DEPTH} exceeded at field "${settingFieldName}".`,
246
+ );
247
+ }
248
+ processedEditor = processDeckEditor(
249
+ settingEditor as DeckContentEditor,
250
+ settingFieldName,
251
+ depth + 1,
252
+ );
253
+ } else {
254
+ processedEditor = processEditorExceptDeck(settingEditor, settingFieldName);
255
+ }
233
256
  editors.push(processedEditor);
234
257
  }
235
258
  defaultCard.editors = editors;
@@ -55,9 +55,18 @@ export const externalContentMock: ExternalContentMock = {
55
55
  url: 'https://www.lightspeedhq.com',
56
56
  target: '_blank',
57
57
  icon: '/assets/lightspeed-icon.png',
58
+ iconSvg: undefined,
58
59
  poweredBy: 'Powered by',
59
60
  company: 'Lightspeed',
60
61
  },
62
+ madeWithV2: {
63
+ url: 'https://www.lightspeedhq.com',
64
+ target: '_blank',
65
+ icon: undefined,
66
+ iconSvg: undefined,
67
+ poweredBy: 'Powered by Lightspeed',
68
+ company: undefined,
69
+ },
61
70
  },
62
71
 
63
72
  category: {
@@ -244,6 +244,9 @@ function parseAccordionDesign(comp: any): Record<string, any> {
244
244
  Object.entries(comp.items || {}).forEach(([itemName, item]: [string, any]) => {
245
245
  const editors: Record<string, any> = {};
246
246
  Object.entries(item.editors || {}).forEach(([editorName, editor]: [string, any]) => {
247
+ if (editor?.type === 'DIVIDER' || editor?.type === 'INFO') {
248
+ return;
249
+ }
247
250
  editors[editorName] = editor.defaults || {};
248
251
  });
249
252
  items[itemName] = { label: item.label, editors };
@@ -40,6 +40,10 @@ export default defineConfig({
40
40
  fs.writeFileSync(analyticsFile, JSON.stringify({}, null, 2), 'utf-8');
41
41
  }
42
42
 
43
+ // Exclude analytics file from Vite's file watcher to prevent
44
+ // HMR triggers when bumpSectionCount writes to it.
45
+ server.watcher.unwatch(analyticsFile);
46
+
43
47
  // helper to bump and persist counter for a given section
44
48
  function bumpSectionCount(section) {
45
49
  const raw = fs.readFileSync(analyticsFile, 'utf-8');
@@ -128,11 +128,11 @@ const {
128
128
  }
129
129
  }
130
130
 
131
- .tag-lines-section::v-deep(.tag-lines-section__highlighted-texts:has(.tag-lines-section__highlighted-text:hover)) .tag-lines-section__highlighted-text {
131
+ .tag-lines-section :deep(.tag-lines-section__highlighted-texts:has(.tag-lines-section__highlighted-text:hover)) .tag-lines-section__highlighted-text {
132
132
  opacity: 0.2;
133
133
  }
134
134
 
135
- .tag-lines-section::v-deep(.tag-lines-section__highlighted-texts:has(.tag-lines-section__highlighted-text:hover)) .tag-lines-section__highlighted-text:hover {
135
+ .tag-lines-section :deep(.tag-lines-section__highlighted-texts:has(.tag-lines-section__highlighted-text:hover)) .tag-lines-section__highlighted-text:hover {
136
136
  opacity: 1;
137
137
  }
138
138
 
@@ -140,13 +140,13 @@ const {
140
140
  transition: opacity ease-in-out 0.3s;
141
141
  }
142
142
 
143
- .tag-lines-section:has(.tag-lines-section__highlighted-text:hover)::v-deep(.section-image__element) {
143
+ .tag-lines-section:has(.tag-lines-section__highlighted-text:hover) :deep(.section-image__element) {
144
144
  opacity: 0;
145
145
  }
146
146
 
147
- .tag-lines-section:has(.tag-lines-section__highlighted-text--1:hover)::v-deep(.section-image__element--1),
148
- .tag-lines-section:has(.tag-lines-section__highlighted-text--2:hover)::v-deep(.section-image__element--2),
149
- .tag-lines-section:has(.tag-lines-section__highlighted-text--3:hover)::v-deep(.section-image__element--3) {
147
+ .tag-lines-section:has(.tag-lines-section__highlighted-text--1:hover) :deep(.section-image__element--1),
148
+ .tag-lines-section:has(.tag-lines-section__highlighted-text--2:hover) :deep(.section-image__element--2),
149
+ .tag-lines-section:has(.tag-lines-section__highlighted-text--3:hover) :deep(.section-image__element--3) {
150
150
  opacity: 1;
151
151
  }
152
152
  </style>
@@ -1 +0,0 @@
1
- module.exports = require('@lightspeed/eslint-config-crane');