@shopware/cms-base-layer 3.1.0 → 4.1.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 (102) hide show
  1. package/README.md +79 -23
  2. package/app/app.config.ts +3 -3
  3. package/app/assets/css/rich-text.css +80 -0
  4. package/app/components/SwCategoryNavigationLink.vue +4 -5
  5. package/app/components/SwContactForm.vue +2 -1
  6. package/app/components/SwFilterChips.vue +29 -7
  7. package/app/components/SwMedia3D.vue +8 -3
  8. package/app/components/SwNewsletterForm.vue +2 -1
  9. package/app/components/SwProductAddToCart.vue +27 -4
  10. package/app/components/SwProductCard.vue +26 -4
  11. package/app/components/SwProductCardDetails.vue +9 -2
  12. package/app/components/SwProductCardImage.vue +5 -1
  13. package/app/components/SwProductListingFilter.vue +6 -1
  14. package/app/components/SwProductListingFilters.vue +13 -189
  15. package/app/components/SwProductListingFiltersHorizontal.vue +20 -172
  16. package/app/components/SwStockInfo.vue +5 -2
  17. package/app/components/SwVariantConfigurator.vue +8 -3
  18. package/app/components/listing-filters/SwFilterCategories.vue +158 -0
  19. package/app/components/public/cms/CmsBlockSpatialViewer.vue +7 -7
  20. package/app/components/public/cms/CmsGenericBlock.vue +6 -10
  21. package/app/components/public/cms/CmsGenericElement.md +11 -5
  22. package/app/components/public/cms/CmsGenericElement.vue +17 -11
  23. package/app/components/public/cms/FrontendAccountCustomerGroupRegistrationPage.vue +1 -1
  24. package/app/components/public/cms/block/CmsBlockAppRenderer.vue +48 -0
  25. package/app/components/public/cms/block/CmsBlockCategoryHeading.vue +19 -0
  26. package/app/components/public/cms/block/CmsBlockCategoryNavigation.vue +3 -2
  27. package/app/components/public/cms/block/CmsBlockCenterText.vue +5 -4
  28. package/app/components/public/cms/block/CmsBlockCrossSelling.vue +3 -2
  29. package/app/components/public/cms/block/CmsBlockCustomForm.vue +3 -2
  30. package/app/components/public/cms/block/CmsBlockForm.vue +3 -2
  31. package/app/components/public/cms/block/CmsBlockGalleryBuybox.vue +4 -3
  32. package/app/components/public/cms/block/CmsBlockImage.vue +3 -2
  33. package/app/components/public/cms/block/CmsBlockImageBubbleRow.vue +5 -4
  34. package/app/components/public/cms/block/CmsBlockImageCover.vue +3 -2
  35. package/app/components/public/cms/block/CmsBlockImageFourColumn.vue +6 -5
  36. package/app/components/public/cms/block/CmsBlockImageGallery.vue +3 -2
  37. package/app/components/public/cms/block/CmsBlockImageGalleryBig.vue +3 -2
  38. package/app/components/public/cms/block/CmsBlockImageHighlightRow.vue +5 -4
  39. package/app/components/public/cms/block/CmsBlockImageSimpleGrid.vue +5 -4
  40. package/app/components/public/cms/block/CmsBlockImageSlider.vue +3 -2
  41. package/app/components/public/cms/block/CmsBlockImageText.vue +4 -3
  42. package/app/components/public/cms/block/CmsBlockImageTextBubble.vue +8 -7
  43. package/app/components/public/cms/block/CmsBlockImageTextCover.vue +4 -3
  44. package/app/components/public/cms/block/CmsBlockImageTextGallery.vue +39 -16
  45. package/app/components/public/cms/block/CmsBlockImageTextRow.vue +8 -7
  46. package/app/components/public/cms/block/CmsBlockImageThreeColumn.vue +5 -4
  47. package/app/components/public/cms/block/CmsBlockImageThreeCover.vue +5 -4
  48. package/app/components/public/cms/block/CmsBlockImageTwoColumn.vue +4 -3
  49. package/app/components/public/cms/block/CmsBlockProductDescriptionReviews.vue +3 -2
  50. package/app/components/public/cms/block/CmsBlockProductHeading.vue +4 -3
  51. package/app/components/public/cms/block/CmsBlockProductListing.vue +3 -2
  52. package/app/components/public/cms/block/CmsBlockProductThreeColumn.vue +5 -4
  53. package/app/components/public/cms/block/CmsBlockSidebarFilter.vue +7 -5
  54. package/app/components/public/cms/block/CmsBlockText.vue +3 -2
  55. package/app/components/public/cms/block/CmsBlockTextHero.vue +3 -2
  56. package/app/components/public/cms/block/CmsBlockTextOnImage.vue +3 -2
  57. package/app/components/public/cms/block/CmsBlockTextThreeColumn.vue +5 -4
  58. package/app/components/public/cms/block/CmsBlockTextTwoColumn.vue +4 -3
  59. package/app/components/public/cms/block/CmsBlockVideo.vue +19 -0
  60. package/app/components/public/cms/block/CmsBlockVimeoVideo.vue +3 -2
  61. package/app/components/public/cms/block/CmsBlockYoutubeVideo.vue +3 -2
  62. package/app/components/public/cms/element/CmsElementBuyBox.vue +4 -1
  63. package/app/components/public/cms/element/CmsElementCategoryName.md +8 -0
  64. package/app/components/public/cms/element/CmsElementCategoryName.vue +35 -0
  65. package/app/components/public/cms/element/CmsElementCrossSelling.vue +2 -1
  66. package/app/components/public/cms/element/CmsElementHtml.vue +1 -1
  67. package/app/components/public/cms/element/CmsElementImage.vue +41 -1
  68. package/app/components/public/cms/element/CmsElementImageGallery.vue +2 -1
  69. package/app/components/public/cms/element/CmsElementProductDescriptionReviews.vue +2 -2
  70. package/app/components/public/cms/element/CmsElementProductListing.vue +58 -25
  71. package/app/components/public/cms/element/CmsElementText.md +77 -0
  72. package/app/components/public/cms/element/CmsElementText.vue +15 -41
  73. package/app/components/public/cms/element/CmsElementVideo.md +27 -0
  74. package/app/components/public/cms/element/CmsElementVideo.vue +193 -0
  75. package/app/components/public/cms/section/CmsSectionSidebar.vue +4 -4
  76. package/app/composables/useListingFilters.ts +189 -0
  77. package/app/composables/useSelectedListingFilters.ts +46 -0
  78. package/app/helpers/cms/getAppRendererLayout.test.ts +93 -0
  79. package/app/helpers/cms/getAppRendererLayout.ts +36 -0
  80. package/app/helpers/cms/getCategoryNameContent.test.ts +57 -0
  81. package/app/helpers/cms/getCategoryNameContent.ts +15 -0
  82. package/app/helpers/cms/getTextElementContent.test.ts +79 -0
  83. package/app/helpers/cms/getTextElementContent.ts +37 -0
  84. package/app/helpers/cms/getVideoElementOptions.test.ts +384 -0
  85. package/app/helpers/cms/getVideoElementOptions.ts +142 -0
  86. package/app/helpers/html-to-vue/renderToHtml.test.ts +71 -0
  87. package/app/helpers/html-to-vue/renderToHtml.ts +5 -1
  88. package/app/helpers/html-to-vue/renderer.ts +13 -4
  89. package/app/helpers/product/shouldShowBuyButton.test.ts +21 -0
  90. package/app/helpers/product/shouldShowBuyButton.ts +6 -0
  91. package/app/utils/{useSelectedListingFilters.test.ts → listingFilterState.test.ts} +14 -4
  92. package/app/utils/{useSelectedListingFilters.ts → listingFilterState.ts} +4 -33
  93. package/app/utils/listingFilters.test.ts +39 -0
  94. package/app/utils/listingFilters.ts +19 -0
  95. package/component-dirs.json +20 -0
  96. package/index.d.ts +2 -2
  97. package/nuxt.config.ts +11 -28
  98. package/package.json +23 -26
  99. package/dist/index.d.mts +0 -5
  100. package/dist/index.d.ts +0 -5
  101. package/dist/index.mjs +0 -31
  102. package/index.cjs +0 -7
@@ -0,0 +1,158 @@
1
+ <script
2
+ setup
3
+ lang="ts"
4
+ generic="
5
+ ListingFilter extends {
6
+ code: string;
7
+ label: string;
8
+ name: string;
9
+ entities?: Array<{
10
+ id: string;
11
+ name?: string;
12
+ translated?: { name?: string };
13
+ }>;
14
+ }
15
+ "
16
+ >
17
+ import { useCmsTranslations } from "@shopware/composables";
18
+ import { excludeRootCategory, getTranslatedProperty } from "@shopware/helpers";
19
+ import { defu } from "defu";
20
+ import { computed, ref } from "vue";
21
+
22
+ import { useSessionContext } from "#imports";
23
+
24
+ const {
25
+ filter,
26
+ selectedFilters,
27
+ displayMode = "accordion",
28
+ } = defineProps<{
29
+ filter: ListingFilter;
30
+ selectedFilters: {
31
+ categories?: string[];
32
+ [key: string]: unknown;
33
+ };
34
+ displayMode?: "accordion" | "dropdown";
35
+ }>();
36
+
37
+ const emits =
38
+ defineEmits<
39
+ (e: "select-value", value: { code: string; value: unknown }) => void
40
+ >();
41
+
42
+ type Translations = {
43
+ listing: {
44
+ categories: string;
45
+ };
46
+ };
47
+
48
+ let translations: Translations = {
49
+ listing: {
50
+ categories: "Categories",
51
+ },
52
+ };
53
+
54
+ translations = defu(useCmsTranslations(), translations) as Translations;
55
+
56
+ const { sessionContext } = useSessionContext();
57
+
58
+ const categoryOptions = computed(() =>
59
+ excludeRootCategory(
60
+ filter.entities,
61
+ sessionContext.value?.salesChannel?.navigationCategoryId,
62
+ ),
63
+ );
64
+
65
+ const isFilterVisible = ref<boolean>(false);
66
+ const toggle = () => {
67
+ isFilterVisible.value = !isFilterVisible.value;
68
+ };
69
+
70
+ const selectedIds = computed(() => selectedFilters?.categories || []);
71
+
72
+ const isChecked = (id: string) => selectedIds.value.includes(id);
73
+
74
+ const selectValue = (id: string) => {
75
+ emits("select-value", {
76
+ code: filter.code,
77
+ value: id,
78
+ });
79
+ };
80
+ </script>
81
+
82
+ <template>
83
+ <div
84
+ v-if="categoryOptions.length"
85
+ class="self-stretch flex flex-col justify-start items-start gap-4"
86
+ >
87
+ <!-- Accordion header (only in accordion mode) -->
88
+ <template v-if="displayMode === 'accordion'">
89
+ <div class="self-stretch flex flex-col justify-center items-center">
90
+ <div
91
+ class="self-stretch py-3 border-b border-outline-outline-variant inline-flex justify-between items-center gap-1 cursor-pointer"
92
+ @click="toggle"
93
+ role="button"
94
+ tabindex="0"
95
+ :aria-expanded="isFilterVisible"
96
+ :aria-controls="filter.code"
97
+ :aria-label="translations.listing.categories"
98
+ @keydown.enter="toggle"
99
+ @keydown.space.prevent="toggle"
100
+ >
101
+ <div class="flex-1 flex items-center gap-2.5">
102
+ <div
103
+ class="flex-1 text-surface-on-surface text-base font-bold leading-normal text-left"
104
+ >
105
+ {{ translations.listing.categories }}
106
+ </div>
107
+ </div>
108
+ <span class="flex items-center justify-center" aria-hidden="true">
109
+ <SwChevronIcon
110
+ :direction="isFilterVisible ? 'up' : 'down'"
111
+ :size="24"
112
+ />
113
+ </span>
114
+ </div>
115
+ </div>
116
+ </template>
117
+
118
+ <!-- Filter content -->
119
+ <transition name="filter-collapse">
120
+ <div
121
+ v-if="isFilterVisible || displayMode === 'dropdown'"
122
+ :id="filter.code"
123
+ class="self-stretch flex flex-col justify-start items-start gap-4"
124
+ >
125
+ <fieldset
126
+ class="self-stretch flex flex-col justify-start items-start gap-4"
127
+ >
128
+ <legend class="sr-only">{{ translations.listing.categories }}</legend>
129
+ <label
130
+ v-for="option in categoryOptions"
131
+ :key="option.id"
132
+ class="self-stretch inline-flex justify-start items-start gap-2 cursor-pointer"
133
+ >
134
+ <div
135
+ class="w-4 self-stretch pt-[3px] flex justify-start items-start gap-2.5"
136
+ >
137
+ <SwCheckbox
138
+ :model-value="isChecked(option.id)"
139
+ @update:model-value="() => selectValue(option.id)"
140
+ />
141
+ </div>
142
+ <div
143
+ class="flex-1 inline-flex flex-col justify-start items-start gap-0.5"
144
+ >
145
+ <div class="inline-flex justify-start items-center gap-1">
146
+ <div
147
+ class="flex-1 text-surface-on-surface text-base font-normal leading-normal"
148
+ >
149
+ {{ getTranslatedProperty(option, "name") }}
150
+ </div>
151
+ </div>
152
+ </div>
153
+ </label>
154
+ </fieldset>
155
+ </div>
156
+ </transition>
157
+ </div>
158
+ </template>
@@ -12,13 +12,13 @@ const props = defineProps<{
12
12
  content: Schemas["CmsBlock"];
13
13
  }>();
14
14
 
15
- const { getSlotContent } = useCmsBlock(props.content);
16
- const slotContent = getSlotContent("default");
15
+ const { getSlotContent } = useCmsBlock(() => props.content);
16
+ const slotContent = computed(() => getSlotContent("default"));
17
17
 
18
18
  function getConfigValue(key: string): unknown {
19
- if (!slotContent?.config) return null;
20
- const configEntry =
21
- slotContent.config[key as keyof typeof slotContent.config];
19
+ const slot = slotContent.value;
20
+ if (!slot?.config) return null;
21
+ const configEntry = slot.config[key as keyof typeof slot.config];
22
22
  if (
23
23
  configEntry &&
24
24
  typeof configEntry === "object" &&
@@ -31,8 +31,8 @@ function getConfigValue(key: string): unknown {
31
31
  }
32
32
 
33
33
  const modelUrl = computed(() => {
34
- if (slotContent?.data) {
35
- const data = slotContent.data as unknown as Schemas["Media"];
34
+ if (slotContent.value?.data) {
35
+ const data = slotContent.value.data as unknown as Schemas["Media"];
36
36
  if (data?.url && typeof data.url === "string") {
37
37
  return data.url;
38
38
  }
@@ -17,22 +17,17 @@ const props = defineProps<{
17
17
 
18
18
  const appConfig = useTypedAppConfig();
19
19
 
20
+ // Plain values, not refs: custom elements inject these as a `number` and a
21
+ // `string` (see the README), so providing a ref here would break them.
20
22
  const slotCount = props.content.slots?.length || 1;
21
23
  provide("cms-block-slot-count", slotCount);
22
24
  provide("cms-image-sizes", getImageSizes(slotCount, appConfig.imageSizes));
23
25
 
24
26
  const DynamicRender = () => {
25
- const {
26
- resolvedComponent,
27
- componentName,
28
- isResolved,
29
- componentNameToResolve,
30
- } = resolveCmsComponent(props.content);
27
+ const { resolvedComponent, componentName, componentNameToResolve } =
28
+ resolveCmsComponent(props.content);
31
29
 
32
30
  if (resolvedComponent) {
33
- if (!isResolved)
34
- return h("div", {}, `Problem resolving component: ${componentName}`);
35
-
36
31
  const { cssClasses, layoutStyles } = getCmsLayoutConfiguration(
37
32
  props.content,
38
33
  );
@@ -75,7 +70,8 @@ const DynamicRender = () => {
75
70
  );
76
71
  return h(resolveComponent("CmsNoComponent"), { content: props.content });
77
72
  }
78
- return h("div", {}, "");
73
+ // Production: a block type with no component renders nothing.
74
+ return null;
79
75
  };
80
76
  </script>
81
77
 
@@ -1,19 +1,25 @@
1
- Renders an Element type structure
1
+ Renders an Element type structure.
2
+
3
+ `content` is optional: `getSlotContent()` returns `undefined` for a slot the block
4
+ does not carry, and this component renders nothing in that case.
2
5
 
3
6
  Example usage:
4
7
 
5
- ```vue{19,22}
8
+ ```vue{22,25}
6
9
  <script setup lang="ts">
7
10
  import type { CmsBlockGalleryBuybox } from "@shopware/composables";
11
+ import { computed } from "vue";
8
12
  import { useCmsBlock } from "#imports";
9
13
 
10
14
  const props = defineProps<{
11
15
  content: CmsBlockGalleryBuybox;
12
16
  }>();
13
17
 
14
- const { getSlotContent } = useCmsBlock(props.content);
15
- const rightContent = getSlotContent("right");
16
- const leftContent = getSlotContent("left");
18
+ // Pass a getter so the lookups follow a replaced block, and read them through
19
+ // computeds so each one re-runs when it does.
20
+ const { getSlotContent } = useCmsBlock(() => props.content);
21
+ const rightContent = computed(() => getSlotContent("right"));
22
+ const leftContent = computed(() => getSlotContent("left"));
17
23
  </script>
18
24
 
19
25
  <template>
@@ -6,20 +6,24 @@ import { h, resolveComponent } from "vue";
6
6
  import type { Schemas } from "#shopware";
7
7
 
8
8
  const props = defineProps<{
9
- content: Schemas["CmsSlot"];
9
+ /**
10
+ * A block asks for its slots by name, and a block does not have to carry
11
+ * every slot its layout allows, so this can be undefined.
12
+ */
13
+ content?: Schemas["CmsSlot"];
10
14
  }>();
11
15
 
12
16
  const DynamicRender = () => {
13
- const {
14
- resolvedComponent,
15
- componentName,
16
- isResolved,
17
- componentNameToResolve,
18
- } = resolveCmsComponent(props.content);
19
- if (resolvedComponent) {
20
- if (!isResolved)
21
- return h("div", {}, `Problem resolving component: ${componentName}`);
17
+ // Nothing to render for a slot the block does not carry. An element would
18
+ // take the class the call site passes and occupy a cell of its own wherever a
19
+ // block renders this straight into a grid, as CmsBlockCenterText does. A
20
+ // wrapper the block puts around the call site renders either way — sizing
21
+ // that wrapper for an absent slot is the block's business, not this one's.
22
+ if (!props.content) return null;
22
23
 
24
+ const { resolvedComponent, componentName, componentNameToResolve } =
25
+ resolveCmsComponent(props.content);
26
+ if (resolvedComponent) {
23
27
  const { cssClasses, layoutStyles } = getCmsLayoutConfiguration(
24
28
  props.content,
25
29
  );
@@ -35,7 +39,9 @@ const DynamicRender = () => {
35
39
  );
36
40
  return h(resolveComponent("CmsNoComponent"), { content: props.content });
37
41
  }
38
- return h("div", {}, "");
42
+ // Production: an element type with no component renders nothing, for the same
43
+ // reason the missing slot above does.
44
+ return null;
39
45
  };
40
46
  </script>
41
47
 
@@ -38,7 +38,7 @@ useSeoMeta({
38
38
  >
39
39
  <div
40
40
  v-if="registrationResponse?.translated.registrationIntroduction"
41
- class="px-6 sm:px-4 mb-6"
41
+ class="cms-element-text px-6 sm:px-4 mb-6"
42
42
  v-html="registrationResponse.translated.registrationIntroduction"
43
43
  />
44
44
  <AccountRegistrationForm
@@ -0,0 +1,48 @@
1
+ <script setup lang="ts">
2
+ import type { CmsBlockAppRenderer } from "@shopware/composables";
3
+ import { computed, getCurrentInstance } from "vue";
4
+ import type { Component, CSSProperties } from "vue";
5
+
6
+ import { getAppRendererLayout } from "../../../../helpers/cms/getAppRendererLayout";
7
+
8
+ const props = defineProps<{
9
+ content: CmsBlockAppRenderer;
10
+ }>();
11
+
12
+ const appContext = getCurrentInstance()?.appContext;
13
+
14
+ const layout = computed(() => getAppRendererLayout(props.content));
15
+
16
+ const appBlockComponent = computed<Component | undefined>(() => {
17
+ const name = layout.value.componentName;
18
+
19
+ return name ? appContext?.components[name] : undefined;
20
+ });
21
+
22
+ const gridStyle = computed<CSSProperties>(() => ({
23
+ display: "grid",
24
+ grid: layout.value.grid,
25
+ }));
26
+ </script>
27
+ <template>
28
+ <component
29
+ :is="appBlockComponent"
30
+ v-if="appBlockComponent"
31
+ :content="content"
32
+ />
33
+ <div
34
+ v-else
35
+ class="cms-block-app-renderer"
36
+ :class="`cms-block-app-renderer-fallback-block-${layout.appBlockName}`"
37
+ :style="gridStyle"
38
+ >
39
+ <div
40
+ v-for="slot in layout.slots"
41
+ :key="slot.id"
42
+ class="min-w-0"
43
+ :class="`cms-block-app-renderer-fallback-slot-${slot.type}`"
44
+ >
45
+ <CmsGenericElement :content="slot" />
46
+ </div>
47
+ </div>
48
+ </template>
@@ -0,0 +1,19 @@
1
+ <script setup lang="ts">
2
+ import type { CmsBlockCategoryHeading } from "@shopware/composables";
3
+ import { computed } from "vue";
4
+
5
+ import { useCmsBlock } from "#imports";
6
+
7
+ const props = defineProps<{
8
+ content: CmsBlockCategoryHeading;
9
+ }>();
10
+
11
+ const { getSlotContent } = useCmsBlock(() => props.content);
12
+
13
+ const slotContent = computed(() => getSlotContent("content"));
14
+ </script>
15
+ <template>
16
+ <div class="cms-block-category-heading">
17
+ <CmsGenericElement :content="slotContent" />
18
+ </div>
19
+ </template>
@@ -1,13 +1,14 @@
1
1
  <script setup lang="ts">
2
2
  import type { CmsBlockCategoryNavigation } from "@shopware/composables";
3
+ import { computed } from "vue";
3
4
 
4
5
  import { useCmsBlock } from "#imports";
5
6
 
6
7
  const props = defineProps<{
7
8
  content: CmsBlockCategoryNavigation;
8
9
  }>();
9
- const { getSlotContent } = useCmsBlock(props.content);
10
- const slotContent = getSlotContent("content");
10
+ const { getSlotContent } = useCmsBlock(() => props.content);
11
+ const slotContent = computed(() => getSlotContent("content"));
11
12
  </script>
12
13
 
13
14
  <template>
@@ -1,5 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import type { CmsBlockCenterText } from "@shopware/composables";
3
+ import { computed } from "vue";
3
4
 
4
5
  import { useCmsBlock } from "#imports";
5
6
 
@@ -7,10 +8,10 @@ const props = defineProps<{
7
8
  content: CmsBlockCenterText;
8
9
  }>();
9
10
 
10
- const { getSlotContent } = useCmsBlock(props.content);
11
- const slotLeftContent = getSlotContent("left");
12
- const slotRightContent = getSlotContent("right");
13
- const slotCenterContent = getSlotContent("center");
11
+ const { getSlotContent } = useCmsBlock(() => props.content);
12
+ const slotLeftContent = computed(() => getSlotContent("left"));
13
+ const slotRightContent = computed(() => getSlotContent("right"));
14
+ const slotCenterContent = computed(() => getSlotContent("center"));
14
15
  </script>
15
16
  <template>
16
17
  <div class="cms-block-center-text grid md:grid-cols-3 gap-10 content-center">
@@ -1,13 +1,14 @@
1
1
  <script setup lang="ts">
2
2
  import type { CmsBlockCrossSelling } from "@shopware/composables";
3
+ import { computed } from "vue";
3
4
 
4
5
  import { useCmsBlock } from "#imports";
5
6
 
6
7
  const props = defineProps<{
7
8
  content: CmsBlockCrossSelling;
8
9
  }>();
9
- const { getSlotContent } = useCmsBlock(props.content);
10
- const slotContent = getSlotContent("content");
10
+ const { getSlotContent } = useCmsBlock(() => props.content);
11
+ const slotContent = computed(() => getSlotContent("content"));
11
12
  </script>
12
13
  <template>
13
14
  <div class="cms-block-cross-selling">
@@ -1,5 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import type { CmsBlockForm } from "@shopware/composables";
3
+ import { computed } from "vue";
3
4
 
4
5
  import { useCmsBlock } from "#imports";
5
6
 
@@ -7,9 +8,9 @@ const props = defineProps<{
7
8
  content: CmsBlockForm;
8
9
  }>();
9
10
 
10
- const { getSlotContent } = useCmsBlock(props.content);
11
+ const { getSlotContent } = useCmsBlock(() => props.content);
11
12
 
12
- const cmsContent = getSlotContent("content");
13
+ const cmsContent = computed(() => getSlotContent("content"));
13
14
  </script>
14
15
  <template>
15
16
  <div class="cms-block-form">
@@ -1,5 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import type { CmsBlockForm } from "@shopware/composables";
3
+ import { computed } from "vue";
3
4
 
4
5
  import { useCmsBlock } from "#imports";
5
6
 
@@ -7,9 +8,9 @@ const props = defineProps<{
7
8
  content: CmsBlockForm;
8
9
  }>();
9
10
 
10
- const { getSlotContent } = useCmsBlock(props.content);
11
+ const { getSlotContent } = useCmsBlock(() => props.content);
11
12
 
12
- const cmsContent = getSlotContent("content");
13
+ const cmsContent = computed(() => getSlotContent("content"));
13
14
  </script>
14
15
  <template>
15
16
  <div class="cms-block-form">
@@ -1,5 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import type { CmsBlockGalleryBuybox } from "@shopware/composables";
3
+ import { computed } from "vue";
3
4
 
4
5
  import { useCmsBlock } from "#imports";
5
6
 
@@ -7,9 +8,9 @@ const props = defineProps<{
7
8
  content: CmsBlockGalleryBuybox;
8
9
  }>();
9
10
 
10
- const { getSlotContent } = useCmsBlock(props.content);
11
- const rightContent = getSlotContent("right");
12
- const leftContent = getSlotContent("left");
11
+ const { getSlotContent } = useCmsBlock(() => props.content);
12
+ const rightContent = computed(() => getSlotContent("right"));
13
+ const leftContent = computed(() => getSlotContent("left"));
13
14
  </script>
14
15
 
15
16
  <template>
@@ -1,5 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import type { CmsBlockImage } from "@shopware/composables";
3
+ import { computed } from "vue";
3
4
 
4
5
  import { useCmsBlock } from "#imports";
5
6
 
@@ -7,8 +8,8 @@ const props = defineProps<{
7
8
  content: CmsBlockImage;
8
9
  }>();
9
10
 
10
- const { getSlotContent } = useCmsBlock(props.content);
11
- const imageContent = getSlotContent("image");
11
+ const { getSlotContent } = useCmsBlock(() => props.content);
12
+ const imageContent = computed(() => getSlotContent("image"));
12
13
  </script>
13
14
  <template>
14
15
  <div>
@@ -1,5 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import type { CmsBlockImageBubbleRow } from "@shopware/composables";
3
+ import { computed } from "vue";
3
4
 
4
5
  import { useCmsBlock } from "#imports";
5
6
 
@@ -7,11 +8,11 @@ const props = defineProps<{
7
8
  content: CmsBlockImageBubbleRow;
8
9
  }>();
9
10
 
10
- const { getSlotContent } = useCmsBlock(props.content);
11
+ const { getSlotContent } = useCmsBlock(() => props.content);
11
12
 
12
- const leftContent = getSlotContent("left");
13
- const rightContent = getSlotContent("right");
14
- const centerContent = getSlotContent("center");
13
+ const leftContent = computed(() => getSlotContent("left"));
14
+ const rightContent = computed(() => getSlotContent("right"));
15
+ const centerContent = computed(() => getSlotContent("center"));
15
16
  </script>
16
17
  <template>
17
18
  <div
@@ -1,5 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import type { CmsBlockImageCover } from "@shopware/composables";
3
+ import { computed } from "vue";
3
4
 
4
5
  import { useCmsBlock } from "#imports";
5
6
 
@@ -7,9 +8,9 @@ const props = defineProps<{
7
8
  content: CmsBlockImageCover;
8
9
  }>();
9
10
 
10
- const { getSlotContent } = useCmsBlock(props.content);
11
+ const { getSlotContent } = useCmsBlock(() => props.content);
11
12
 
12
- const cmsContent = getSlotContent("image");
13
+ const cmsContent = computed(() => getSlotContent("image"));
13
14
  </script>
14
15
  <template>
15
16
  <div class="cms-block-image-cover">
@@ -1,5 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import type { CmsBlockImageFourColumn } from "@shopware/composables";
3
+ import { computed } from "vue";
3
4
 
4
5
  import { useCmsBlock } from "#imports";
5
6
 
@@ -7,12 +8,12 @@ const props = defineProps<{
7
8
  content: CmsBlockImageFourColumn;
8
9
  }>();
9
10
 
10
- const { getSlotContent } = useCmsBlock(props.content);
11
+ const { getSlotContent } = useCmsBlock(() => props.content);
11
12
 
12
- const leftContent = getSlotContent("left");
13
- const rightContent = getSlotContent("right");
14
- const centerLeftContent = getSlotContent("center-left");
15
- const centerRightContent = getSlotContent("center-right");
13
+ const leftContent = computed(() => getSlotContent("left"));
14
+ const rightContent = computed(() => getSlotContent("right"));
15
+ const centerLeftContent = computed(() => getSlotContent("center-left"));
16
+ const centerRightContent = computed(() => getSlotContent("center-right"));
16
17
  </script>
17
18
  <template>
18
19
  <div
@@ -1,5 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import type { CmsBlockImageGallery } from "@shopware/composables";
3
+ import { computed } from "vue";
3
4
 
4
5
  import { useCmsBlock } from "#imports";
5
6
 
@@ -7,9 +8,9 @@ const props = defineProps<{
7
8
  content: CmsBlockImageGallery;
8
9
  }>();
9
10
 
10
- const { getSlotContent } = useCmsBlock(props.content);
11
+ const { getSlotContent } = useCmsBlock(() => props.content);
11
12
 
12
- const cmsContent = getSlotContent("imageGallery");
13
+ const cmsContent = computed(() => getSlotContent("imageGallery"));
13
14
  </script>
14
15
 
15
16
  <template>
@@ -1,5 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import type { CmsBlockImageGalleryBig } from "@shopware/composables";
3
+ import { computed } from "vue";
3
4
 
4
5
  import { useCmsBlock } from "#imports";
5
6
 
@@ -7,9 +8,9 @@ const props = defineProps<{
7
8
  content: CmsBlockImageGalleryBig;
8
9
  }>();
9
10
 
10
- const { getSlotContent } = useCmsBlock(props.content);
11
+ const { getSlotContent } = useCmsBlock(() => props.content);
11
12
 
12
- const cmsContent = getSlotContent("imageGallery");
13
+ const cmsContent = computed(() => getSlotContent("imageGallery"));
13
14
  </script>
14
15
 
15
16
  <template>
@@ -1,5 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import type { CmsBlockImageHighlightRow } from "@shopware/composables";
3
+ import { computed } from "vue";
3
4
 
4
5
  import { useCmsBlock } from "#imports";
5
6
 
@@ -7,11 +8,11 @@ const props = defineProps<{
7
8
  content: CmsBlockImageHighlightRow;
8
9
  }>();
9
10
 
10
- const { getSlotContent } = useCmsBlock(props.content);
11
+ const { getSlotContent } = useCmsBlock(() => props.content);
11
12
 
12
- const leftContent = getSlotContent("left");
13
- const rightContent = getSlotContent("right");
14
- const centerContent = getSlotContent("center");
13
+ const leftContent = computed(() => getSlotContent("left"));
14
+ const rightContent = computed(() => getSlotContent("right"));
15
+ const centerContent = computed(() => getSlotContent("center"));
15
16
  </script>
16
17
  <template>
17
18
  <div