@shopware/cms-base-layer 3.1.0 → 4.0.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.
Files changed (37) hide show
  1. package/README.md +64 -23
  2. package/app/app.config.ts +3 -3
  3. package/app/assets/css/rich-text.css +80 -0
  4. package/app/components/SwContactForm.vue +2 -1
  5. package/app/components/SwFilterChips.vue +29 -7
  6. package/app/components/SwNewsletterForm.vue +2 -1
  7. package/app/components/SwProductCardImage.vue +5 -1
  8. package/app/components/SwProductListingFilter.vue +5 -0
  9. package/app/components/SwProductListingFilters.vue +40 -4
  10. package/app/components/SwProductListingFiltersHorizontal.vue +37 -2
  11. package/app/components/SwStockInfo.vue +5 -2
  12. package/app/components/SwVariantConfigurator.vue +8 -3
  13. package/app/components/listing-filters/SwFilterCategories.vue +158 -0
  14. package/app/components/public/cms/FrontendAccountCustomerGroupRegistrationPage.vue +1 -1
  15. package/app/components/public/cms/element/CmsElementBuyBox.vue +4 -1
  16. package/app/components/public/cms/element/CmsElementCrossSelling.vue +2 -1
  17. package/app/components/public/cms/element/CmsElementHtml.vue +1 -1
  18. package/app/components/public/cms/element/CmsElementImage.vue +41 -1
  19. package/app/components/public/cms/element/CmsElementImageGallery.vue +2 -1
  20. package/app/components/public/cms/element/CmsElementProductDescriptionReviews.vue +2 -2
  21. package/app/components/public/cms/element/CmsElementText.md +77 -0
  22. package/app/components/public/cms/element/CmsElementText.vue +5 -32
  23. package/app/helpers/html-to-vue/renderToHtml.test.ts +55 -0
  24. package/app/helpers/html-to-vue/renderToHtml.ts +5 -1
  25. package/app/helpers/html-to-vue/renderer.ts +10 -1
  26. package/app/utils/listingFilters.test.ts +39 -0
  27. package/app/utils/listingFilters.ts +19 -0
  28. package/app/utils/useSelectedListingFilters.test.ts +13 -3
  29. package/app/utils/useSelectedListingFilters.ts +7 -1
  30. package/component-dirs.json +20 -0
  31. package/index.d.ts +2 -2
  32. package/nuxt.config.ts +11 -28
  33. package/package.json +20 -23
  34. package/dist/index.d.mts +0 -5
  35. package/dist/index.d.ts +0 -5
  36. package/dist/index.mjs +0 -31
  37. package/index.cjs +0 -7
@@ -8,17 +8,27 @@ import {
8
8
  describe("applyQueryToFilters", () => {
9
9
  it("populates sets from pipe-joined values", () => {
10
10
  const state = createEmptyFilterState();
11
- applyQueryToFilters(state, { manufacturer: "a|b", properties: "x" });
11
+ applyQueryToFilters(state, {
12
+ manufacturer: "a|b",
13
+ properties: "x",
14
+ categories: "c1|c2",
15
+ });
12
16
  expect([...state.manufacturer]).toEqual(["a", "b"]);
13
17
  expect([...state.properties]).toEqual(["x"]);
18
+ expect([...state.categories]).toEqual(["c1", "c2"]);
14
19
  });
15
20
 
16
21
  it("clears removed filters when the query no longer has them (Back/Forward)", () => {
17
22
  const state = createEmptyFilterState();
18
- applyQueryToFilters(state, { manufacturer: "a|b", search: "shirt" });
19
- applyQueryToFilters(state, { search: "shirt" }); // manufacturer removed
23
+ applyQueryToFilters(state, {
24
+ manufacturer: "a|b",
25
+ categories: "c1",
26
+ search: "shirt",
27
+ });
28
+ applyQueryToFilters(state, { search: "shirt" }); // manufacturer + categories removed
20
29
  expect(state.manufacturer.size).toBe(0);
21
30
  expect(state.properties.size).toBe(0);
31
+ expect(state.categories.size).toBe(0);
22
32
  });
23
33
 
24
34
  it("clears removed scalar filters on resync", () => {
@@ -8,6 +8,7 @@ import { firstQueryValue, toNumber } from "./routeQuery";
8
8
  export type FilterState = {
9
9
  manufacturer: Set<string>;
10
10
  properties: Set<string>;
11
+ categories: Set<string>;
11
12
  "min-price": number | undefined;
12
13
  "max-price": number | undefined;
13
14
  rating: number | undefined;
@@ -18,6 +19,7 @@ export type FilterState = {
18
19
  export const createEmptyFilterState = (): FilterState => ({
19
20
  manufacturer: new Set<string>(),
20
21
  properties: new Set<string>(),
22
+ categories: new Set<string>(),
21
23
  "min-price": undefined,
22
24
  "max-price": undefined,
23
25
  rating: undefined,
@@ -46,13 +48,14 @@ export const applyQueryToFilters = (
46
48
  // (props bound to them stay reactive); replace scalars with undefined.
47
49
  state.manufacturer.clear();
48
50
  state.properties.clear();
51
+ state.categories.clear();
49
52
  state["min-price"] = undefined;
50
53
  state["max-price"] = undefined;
51
54
  state.rating = undefined;
52
55
  state["shipping-free"] = undefined;
53
56
 
54
57
  // 2) Repopulate from the current query.
55
- for (const code of ["manufacturer", "properties"] as const) {
58
+ for (const code of ["manufacturer", "properties", "categories"] as const) {
56
59
  const value = firstQueryValue(query[code]);
57
60
  if (!value) continue;
58
61
  for (const element of value.split("|")) {
@@ -88,6 +91,9 @@ export const applyQueryToFilters = (
88
91
  */
89
92
  export const useSelectedListingFilters = (): UnwrapNestedRefs<FilterState> => {
90
93
  const route = useRoute();
94
+ // Fresh state per call, deliberately: the sidebar and the horizontal filter
95
+ // bar each hold their own selection object, so a mutation in one is invisible
96
+ // to the other until it reaches the route. The URL is what synchronises them.
91
97
  const state = reactive<FilterState>(createEmptyFilterState());
92
98
 
93
99
  // Initial parse (SSR + first client render).
@@ -0,0 +1,20 @@
1
+ {
2
+ "dirs": [
3
+ {
4
+ "path": "./app/components",
5
+ "pattern": "Sw*",
6
+ "global": true
7
+ },
8
+ {
9
+ "path": "./app/components/public",
10
+ "pathPrefix": false,
11
+ "global": true
12
+ },
13
+ {
14
+ "path": "./app/components/ui",
15
+ "prefix": "Sw",
16
+ "global": true
17
+ }
18
+ ],
19
+ "excluded": ["SwMedia3D"]
20
+ }
package/index.d.ts CHANGED
@@ -1,7 +1,5 @@
1
1
  /// <reference types="@nuxt/schema" />
2
2
 
3
- export * from "@shopware/composables";
4
- export * from "./.nuxt/imports";
5
3
 
6
4
  type CmsBaseLayerAppConfig = {
7
5
  /** Placeholder shown while CMS images are loading */
@@ -42,3 +40,5 @@ declare module "@nuxt/schema" {
42
40
  interface AppConfig extends CmsBaseLayerAppConfig {}
43
41
  interface AppConfigInput extends CmsBaseLayerAppConfig {}
44
42
  }
43
+
44
+ export {};
package/nuxt.config.ts CHANGED
@@ -3,6 +3,8 @@ import type { NuxtConfig } from "@nuxt/schema";
3
3
  import { defineNuxtConfig } from "nuxt/config";
4
4
  import type { LoggingFunction, RollupLog } from "rollup";
5
5
 
6
+ import componentDirs from "./component-dirs.json";
7
+
6
8
  const { resolve: resolveLayer } = createResolver(import.meta.url);
7
9
 
8
10
  export default defineNuxtConfig({
@@ -15,19 +17,15 @@ export default defineNuxtConfig({
15
17
  // the UnoCSS setup lives in @shopware/unocss-design-tokens-layer (or your own config),
16
18
  // so apps that don't use UnoCSS can still extend this layer.
17
19
  modules: ["@nuxt/image"],
20
+ css: [resolveLayer("./app/assets/css/rich-text.css")],
18
21
 
19
22
  hooks: {
20
23
  "components:extend"(components) {
21
24
  // Exclude SwMedia3D from auto-import to prevent bundling heavy 3D libraries
22
25
  // It should be dynamically imported when needed using defineAsyncComponent.
23
- const index = components.findIndex(
24
- (c) =>
25
- c.pascalName === "SwMedia3D" ||
26
- c.kebabName === "sw-media3-d" ||
27
- c.filePath?.includes("SwMedia3D.vue"),
28
- );
29
- if (index > -1) {
30
- components.splice(index, 1);
26
+ for (const name of componentDirs.excluded) {
27
+ const index = components.findIndex((c) => c.pascalName === name);
28
+ if (index > -1) components.splice(index, 1);
31
29
  }
32
30
  },
33
31
  },
@@ -90,26 +88,11 @@ export default defineNuxtConfig({
90
88
  },
91
89
  },
92
90
 
93
- components: [
94
- {
95
- path: resolveLayer("./app/components"),
96
- pattern: "Sw*",
97
- extensions: [".vue"],
98
- global: true,
99
- },
100
- {
101
- path: resolveLayer("./app/components/ui"),
102
- extensions: [".vue"],
103
- prefix: "Sw",
104
- global: true,
105
- },
106
- {
107
- path: resolveLayer("./app/components/public"),
108
- pathPrefix: false,
109
- global: true,
110
- extensions: [".vue"],
111
- },
112
- ],
91
+ components: componentDirs.dirs.map(({ path, ...dir }) => ({
92
+ ...dir,
93
+ path: resolveLayer(path),
94
+ extensions: [".vue"],
95
+ })),
113
96
  alias: {
114
97
  "@cms-assets": resolveLayer("./app/assets"),
115
98
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shopware/cms-base-layer",
3
- "version": "3.1.0",
3
+ "version": "4.0.0",
4
4
  "description": "Vue CMS Nuxt Layer for Shopware",
5
5
  "author": "Shopware",
6
6
  "repository": {
@@ -21,20 +21,21 @@
21
21
  "license": "MIT",
22
22
  "type": "module",
23
23
  "main": "./nuxt.config.ts",
24
+ "exports": {
25
+ ".": "./nuxt.config.ts",
26
+ "./package.json": "./package.json"
27
+ },
24
28
  "files": [
25
- "dist",
26
29
  "app",
27
- "helpers",
28
- "index.cjs",
30
+ "component-dirs.json",
29
31
  "index.d.ts",
30
- "app.config.ts",
31
32
  "nuxt.config.ts"
32
33
  ],
33
34
  "dependencies": {
34
- "@iconify-json/carbon": "1.2.24",
35
- "@nuxt/image": "2.0.0",
36
- "@nuxt/kit": "4.4.8",
37
- "@tresjs/cientos": "5.7.2",
35
+ "@iconify-json/carbon": "1.2.26",
36
+ "@nuxt/image": "2.1.0",
37
+ "@nuxt/kit": "4.5.2",
38
+ "@tresjs/cientos": "5.8.1",
38
39
  "@tresjs/nuxt": "^5.6.3",
39
40
  "@vuelidate/core": "2.0.3",
40
41
  "@vuelidate/validators": "2.0.4",
@@ -42,34 +43,30 @@
42
43
  "entities": "8.0.0",
43
44
  "scule": "1.3.0",
44
45
  "html-to-ast": "0.0.6",
45
- "three": "0.183.2",
46
- "vue": "3.5.39",
46
+ "three": "0.185.1",
47
+ "vue": "3.5.42",
47
48
  "xss": "1.0.15",
48
- "@shopware/api-client": "1.5.1",
49
- "@shopware/composables": "1.12.1",
50
- "@shopware/helpers": "1.7.2"
49
+ "@shopware/composables": "1.13.0",
50
+ "@shopware/api-client": "1.6.0",
51
+ "@shopware/helpers": "1.8.0"
51
52
  },
52
53
  "devDependencies": {
53
- "@nuxt/schema": "4.4.8",
54
+ "@nuxt/schema": "4.5.2",
54
55
  "@types/three": "0.182.0",
55
56
  "@typescript/native-preview": "7.0.0-dev.20260205.1",
56
57
  "@vitest/coverage-v8": "4.1.10",
57
- "nuxt": "4.4.8",
58
+ "nuxt": "4.5.2",
58
59
  "typescript": "5.9.3",
59
- "unbuild": "3.6.1",
60
60
  "vitest": "4.1.10",
61
- "vue-router": "5.1.0",
62
- "vue-tsc": "3.3.7",
61
+ "vue-router": "5.2.0",
62
+ "vue-tsc": "3.3.9",
63
63
  "tsconfig": "0.0.0"
64
64
  },
65
65
  "scripts": {
66
- "build": "nuxt prepare && unbuild",
67
- "dev": "unbuild --stub",
68
66
  "lint": "oxlint . && oxfmt --check .",
69
67
  "lint:fix": "oxlint --fix . && oxfmt --write . && pnpm run typecheck",
70
68
  "typecheck": "pnpm nuxt prepare && tsgo --noEmit",
71
69
  "test": "vitest run",
72
- "test:watch": "vitest",
73
- "check-colors": "tsx scripts/check-unused-colors.ts"
70
+ "test:watch": "vitest"
74
71
  }
75
72
  }
package/dist/index.d.mts DELETED
@@ -1,5 +0,0 @@
1
- import * as _nuxt_schema from '@nuxt/schema';
2
-
3
- declare const _default: _nuxt_schema.NuxtModule<_nuxt_schema.ModuleOptions, _nuxt_schema.ModuleOptions, false>;
4
-
5
- export { _default as default };
package/dist/index.d.ts DELETED
@@ -1,5 +0,0 @@
1
- import * as _nuxt_schema from '@nuxt/schema';
2
-
3
- declare const _default: _nuxt_schema.NuxtModule<_nuxt_schema.ModuleOptions, _nuxt_schema.ModuleOptions, false>;
4
-
5
- export { _default as default };
package/dist/index.mjs DELETED
@@ -1,31 +0,0 @@
1
- import { resolve } from 'node:path';
2
- import { defineNuxtModule } from '@nuxt/kit';
3
-
4
-
5
-
6
- // -- Unbuild CommonJS Shims --
7
- import __cjs_url__ from 'url';
8
- import __cjs_path__ from 'path';
9
- import __cjs_mod__ from 'module';
10
- const __filename = __cjs_url__.fileURLToPath(import.meta.url);
11
- const __dirname = __cjs_path__.dirname(__filename);
12
- const require = __cjs_mod__.createRequire(import.meta.url);
13
- const index = defineNuxtModule({
14
- meta: {
15
- name: "@shopware/cms-base",
16
- configKey: "shopware-cms"
17
- },
18
- setup(_, nuxt) {
19
- nuxt.hook("components:dirs", (c) => {
20
- c.push({
21
- path: resolve(__dirname, "../components/public"),
22
- global: true
23
- });
24
- });
25
- nuxt.options.imports.transform = nuxt.options.imports.transform || {};
26
- nuxt.options.imports.transform.include = nuxt.options.imports.transform?.include || [];
27
- nuxt.options.imports.transform?.include.push(/.+cms-base.+/);
28
- }
29
- });
30
-
31
- export { index as default };
package/index.cjs DELETED
@@ -1,7 +0,0 @@
1
- // CommonJS proxy to bypass jiti transforms from nuxt 2 and using native ESM
2
- module.exports = function (...args) {
3
- return import("./dist/index.mjs").then((m) => m.default.call(this, ...args));
4
- };
5
-
6
- // eslint-disable-next-line
7
- module.exports.meta = require("./package.json");