@explorer-1/vue 0.2.85 → 0.2.86

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": "@explorer-1/vue",
3
- "version": "0.2.85",
3
+ "version": "0.2.86",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -30,7 +30,7 @@
30
30
  "vue-bind-once": "^0.2.1",
31
31
  "vue3-compare-image": "^1.2.5",
32
32
  "vue3-observe-visibility": "^1.0.1",
33
- "@explorer-1/common": "1.1.21"
33
+ "@explorer-1/common": "1.1.23"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@vitejs/plugin-vue": "^5.0.4",
@@ -44,7 +44,7 @@ export const BlockStreamfieldMinimalData = {
44
44
  {
45
45
  blockType: 'RichTextBlock',
46
46
  value:
47
- '<p>Lorem ipsum <a href="/missions/test-mission/">dolor</a> sit amet, consectetur adipiscing elit. Quisque vitae justo quis justo malesuada molestie. Cras sed tincidunt dui.</p>\n'
47
+ '<p>Lorem ipsum <a href="/missions/test-mission/">dolor</a> sit amet, consectetur adipiscing elit. Quisque vitae justo quis justo malesuada molestie. Cras sed tincidunt dui.</p><h2 data-block-key="cba9u">A heading in BlockText</h2><p>Lorem ipsum <a href="/missions/test-mission/">dolor</a> sit amet, consectetur adipiscing elit.</p><h3 data-block-key="ujfka8">A heading in BlockText</h3><p>Quisque vitae justo quis justo malesuada molestie.</p><h2 data-block-key="ujfka8">A heading in BlockText</h2><p>Cras sed tincidunt dui.</p>\n'
48
48
  },
49
49
  {
50
50
  blockType: 'RichTextBlock',
@@ -59,7 +59,7 @@ export const BlockStreamfieldTruncatedData = {
59
59
  {
60
60
  blockType: 'RichTextBlock',
61
61
  value:
62
- '<p>Lorem ipsum <a href="/missions/test-mission/">dolor</a> sit amet, consectetur adipiscing elit. Quisque vitae justo quis justo malesuada molestie. Cras sed tincidunt dui.</p><p>Integer imperdiet blandit neque vitae euismod. Nulla aliquet lacus nibh, vel tincidunt urna efficitur non. In et eros vitae ex posuere maximus quis eget urna. Suspendisse fringilla posuere velit sit amet posuere. Morbi malesuada bibendum vehicula. Donec faucibus ut erat ut mattis. Suspendisse ornare, quam at placerat cursus, dolor mi lacinia nunc, eget maximus augue nulla in dolor.</p>\n'
62
+ '<p>Lorem ipsum <a href="/missions/test-mission/">dolor</a> sit amet, consectetur adipiscing elit. Quisque vitae justo quis justo malesuada molestie. Cras sed tincidunt dui.</p><h2 data-block-key="cba9u">A heading in BlockText</h2><p>Lorem ipsum <a href="/missions/test-mission/">dolor</a> sit amet, consectetur adipiscing elit.</p><h3 data-block-key="ujfka8">A heading in BlockText</h3><p>Quisque vitae justo quis justo malesuada molestie.</p><h2 data-block-key="ujfka8">A heading in BlockText</h2><p>Cras sed tincidunt dui.</p>\n'
63
63
  },
64
64
  { ...BlockHeadingData, blockId: Math.random().toString(36).slice(2) },
65
65
  {
@@ -19,13 +19,13 @@ export default {
19
19
  excludeStories: /.*Data$/
20
20
  }
21
21
 
22
- export const RichTextMediaData = `<h2>A heading in BlockText</h2><p data-block-key="5f55p">Description for it.</p><div class="richtext-image fullwidth"><img alt="Perseverance Looks Back at &amp;#x27;Bright Angel&amp;#x27;" height="480" loading="lazy" src="https://picsum.photos/640/480" width="640">
22
+ export const RichTextMediaData = `<h2 data-block-key="cba9u">A heading in BlockText</h2><p data-block-key="5f55p">Description for it.</p><div class="richtext-image fullwidth"><img alt="Perseverance Looks Back at &amp;#x27;Bright Angel&amp;#x27;" height="480" loading="lazy" src="https://picsum.photos/640/480" width="640">
23
23
  <div class="richtext-caption">
24
24
  <div class="caption">One of the navigation cameras aboard NASAs Perseverance Mars rover captured this view looking back at the Bright Angel area on July 30, 2024.</div>
25
25
  <span class="credit">Credit: NASA/JPL-Caltech</span>
26
26
  <a class="caption-link" href="#">Full Image Details</a>
27
27
  </div>
28
- </div><h3>Subheading in BlockText</h3><p data-block-key="89jcq">More text and another image that&#x27;s full width (above)</p><p data-block-key="6jsp"></p><div class="richtext-image left"><img alt="Carbon Mapper Coalition&amp;#x27;s Tanager Satellite" height="336" loading="lazy" src="https://picsum.photos/640/336" width="640">
28
+ </div><h3 data-block-key="ois8du">Subheading in BlockText</h3><p data-block-key="89jcq">More text and another image that&#x27;s full width (above)</p><p data-block-key="6jsp"></p><div class="richtext-image left"><img alt="Carbon Mapper Coalition&amp;#x27;s Tanager Satellite" height="336" loading="lazy" src="https://picsum.photos/640/336" width="640">
29
29
  <div class="richtext-caption">
30
30
  <div class="caption">This artists concept depicts one of the Carbon Mapper Coalitions Tanager satellites, the first of which launched on Aug. 16, 2024. Tanager-1 will use imaging spectrometer technology developed at JPL to measure greenhouse gas point-source emissions.</div>
31
31
  <span class="credit">Credit: Planet Labs PBC</span>
@@ -12,6 +12,10 @@ interface Variants {
12
12
  [key: string]: string
13
13
  }
14
14
 
15
+ export interface BlockTextObject {
16
+ blockType?: string
17
+ value: string
18
+ }
15
19
  export const variants: Variants = {
16
20
  small: 'text-body-sm -small',
17
21
  medium: 'text-body-md -medium',
@@ -45,19 +45,18 @@ import NavSecondaryDropdown from './../NavSecondary/NavSecondaryDropdown.vue'
45
45
  import NavSecondaryLink from './../NavSecondary/NavSecondaryLink.vue'
46
46
  import NavJumpMenuContent from './../NavJumpMenu/NavJumpMenuContent.vue'
47
47
  import type { BlockHeadingObject } from './../BlockHeading/BlockHeading.vue'
48
- import type { BlockData, BreadcrumbPathObject } from './../../interfaces'
48
+ import type { BlockTextObject } from './../BlockText/BlockText.vue'
49
+ import type { BlockData, BreadcrumbPathObject, StreamfieldBlockData } from './../../interfaces'
49
50
  import { getHeadingId } from '../../utils/getHeadingId'
50
51
 
51
52
  interface NavJumpMenuProps {
52
53
  title?: string
53
54
  jumpLinks?: BreadcrumbPathObject[]
54
- blocks?: BlockData[] | BlockHeadingObject[]
55
+ blocks?: (StreamfieldBlockData | BlockData | BlockHeadingObject | BlockTextObject)[]
55
56
  headingLevel?: string
56
57
  invert?: boolean
57
58
  enabled?: boolean
58
59
  dropdownText?: string
59
- // stepsNumbering?: boolean
60
- // stepClasses?: string
61
60
  }
62
61
 
63
62
  const props = withDefaults(defineProps<NavJumpMenuProps>(), {
@@ -69,8 +68,6 @@ const props = withDefaults(defineProps<NavJumpMenuProps>(), {
69
68
  invert: true,
70
69
  hidden: false,
71
70
  dropdownText: 'Jump to…'
72
- // stepsNumbering: false,
73
- // stepClasses: 'text-primary'
74
71
  })
75
72
 
76
73
  const initialized = ref(false)
@@ -88,17 +85,47 @@ const theJumpLinks = computed(() => {
88
85
  }
89
86
  })
90
87
  const filteredBlocks = indexedBlocks.filter((b) => {
91
- return b.blockType === 'HeadingBlock' && b.level === props.headingLevel
88
+ return (
89
+ (b.blockType === 'HeadingBlock' &&
90
+ (b as BlockHeadingObject).level === props.headingLevel) ||
91
+ (b.blockType === 'RichTextBlock' &&
92
+ (b as BlockTextObject).value.includes(`<${props.headingLevel}`))
93
+ )
92
94
  })
93
95
  // map to the correct data shape
94
- const links: BreadcrumbPathObject[] = filteredBlocks.map((h) => {
95
- return {
96
- // @ts-expect-error using parameter that was added to BlockData
97
- path: '#' + getHeadingId(h.heading, h.blockId),
98
- title: h.heading
99
- } as BreadcrumbPathObject
96
+ const links: (BreadcrumbPathObject | BreadcrumbPathObject[])[] = filteredBlocks.map((h) => {
97
+ let block = h
98
+ let blocks = []
99
+ if (h.blockType === 'HeadingBlock') {
100
+ block = {
101
+ // @ts-expect-error using parameter that was added to BlockData
102
+ path: '#' + getHeadingId(h.heading, h.blockId),
103
+ title: (h as BlockHeadingObject).heading
104
+ }
105
+ } else if (h.blockType === 'RichTextBlock') {
106
+ let text = (h as BlockTextObject).value
107
+ if (text) {
108
+ const regex = new RegExp(
109
+ `<${props.headingLevel} id="(.*?)">(.*?)</${props.headingLevel}>`,
110
+ 'g'
111
+ )
112
+ const matches = text.matchAll(regex)
113
+ const headings = [...matches]
114
+ for (let arr of headings) {
115
+ const [_match, g1, g2] = arr
116
+ const block = {
117
+ path: '#' + g1,
118
+ title: g2
119
+ }
120
+ blocks.push(block)
121
+ }
122
+ }
123
+ }
124
+ return blocks.length
125
+ ? (blocks as unknown as BreadcrumbPathObject[])
126
+ : (block as unknown as BreadcrumbPathObject)
100
127
  })
101
- return links
128
+ return links ? links.flat() : undefined
102
129
  }
103
130
  return []
104
131
  })
@@ -12,6 +12,7 @@ import NavJumpMenu from './../../../components/NavJumpMenu/NavJumpMenu.vue'
12
12
  import NavSecondary from './../../../components/NavSecondary/NavSecondary.vue'
13
13
  import MetaPanel from '../../../components/MetaPanel/MetaPanel.vue'
14
14
  import ShareButtonsEdu from '../../../components/ShareButtonsEdu/ShareButtonsEdu.vue'
15
+ import { anchorizeStreamfield } from './../../../utils/anchorizeStreamfield'
15
16
 
16
17
  interface PageEduCollectionsDetail extends PageEduResourcesObject {
17
18
  heroImage: ImageObject
@@ -39,6 +40,11 @@ const heroInline = computed((): boolean => {
39
40
  return data?.heroPosition === 'inline'
40
41
  })
41
42
 
43
+ const filteredBody = computed(() => {
44
+ // adds anchors to headings within RichTextBlock
45
+ return anchorizeStreamfield(data?.body)
46
+ })
47
+
42
48
  const computedClass = computed((): string => {
43
49
  if ((heroInline.value || !data?.heroImage) && !data?.breadcrumb) {
44
50
  return 'pt-5 lg:pt-12'
@@ -58,7 +64,7 @@ const computedClass = computed((): string => {
58
64
  v-if="data.showJumpMenu && !data.breadcrumb"
59
65
  ref="PageEduCollectionsDetailJumpMenu"
60
66
  :title="data.title"
61
- :blocks="data.body"
67
+ :blocks="filteredBody"
62
68
  dropdown-text="In this collection"
63
69
  />
64
70
 
@@ -69,7 +75,7 @@ const computedClass = computed((): string => {
69
75
  :image="data.heroImage"
70
76
  :summary="data.heroSummary"
71
77
  :custom-pill-type="data.__typename"
72
- :class="!data.showMetaPanel ? 'mb-10' : ''"
78
+ :class="!data.showMetaPanel && !data.breadcrumb ? 'mb-10' : ''"
73
79
  />
74
80
 
75
81
  <!-- secondary nav -->
@@ -137,7 +143,7 @@ const computedClass = computed((): string => {
137
143
  </LayoutHelper>
138
144
 
139
145
  <!-- streamfield blocks -->
140
- <BlockStreamfield :data="data.body" />
146
+ <BlockStreamfield :data="filteredBody" />
141
147
 
142
148
  <!-- related links -->
143
149
  <LayoutHelper
@@ -12,6 +12,7 @@ import BlockRelatedLinks from '../../../components/BlockRelatedLinks/BlockRelate
12
12
  import NavJumpMenu from './../../../components/NavJumpMenu/NavJumpMenu.vue'
13
13
  import HeroInlineMedia from './../../../components/HeroInlineMedia/HeroInlineMedia.vue'
14
14
  import AboutTheAuthor from './../../../components/AboutTheAuthor/AboutTheAuthor.vue'
15
+ import { anchorizeStreamfield } from './../../../utils/anchorizeStreamfield'
15
16
 
16
17
  export default defineComponent({
17
18
  name: 'PageEduExplainerArticle',
@@ -71,6 +72,10 @@ export default defineComponent({
71
72
  }
72
73
  return false
73
74
  },
75
+ filteredBody() {
76
+ // adds anchors to headings within RichTextBlock
77
+ return anchorizeStreamfield(this.data?.body)
78
+ },
74
79
  computedClass(): string {
75
80
  if (this.heroInline || this.heroEmpty) {
76
81
  return 'pt-5 lg:pt-12'
@@ -100,7 +105,7 @@ export default defineComponent({
100
105
  <NavJumpMenu
101
106
  v-if="data.showJumpMenu"
102
107
  :title="data.title"
103
- :blocks="data.body"
108
+ :blocks="filteredBody"
104
109
  dropdown-text="In this article"
105
110
  />
106
111
 
@@ -182,7 +187,7 @@ export default defineComponent({
182
187
  <!-- streamfield blocks -->
183
188
  <BlockStreamfield
184
189
  itemprop="articleBody"
185
- :data="data.body"
190
+ :data="filteredBody"
186
191
  />
187
192
 
188
193
  <!-- related links -->
@@ -20,6 +20,7 @@ import BlockStreamfield from './../../../components/BlockStreamfield/BlockStream
20
20
  import NavJumpMenu from './../../../components/NavJumpMenu/NavJumpMenu.vue'
21
21
  import AboutTheAuthor from './../../../components/AboutTheAuthor/AboutTheAuthor.vue'
22
22
  import { getHeadingId } from '../../../utils/getHeadingId'
23
+
23
24
  interface PageEduGalleryObject extends PageEduResourcesObject {
24
25
  overviewString?: string
25
26
  galleryItems?: {
@@ -20,8 +20,8 @@ import PageEduLessonSection, { type PageEduLessonSectionProps } from './PageEduL
20
20
  import NavJumpMenu from './../../../components/NavJumpMenu/NavJumpMenu.vue'
21
21
  import HeroInlineMedia from './../../../components/HeroInlineMedia/HeroInlineMedia.vue'
22
22
  import AboutTheAuthor from './../../../components/AboutTheAuthor/AboutTheAuthor.vue'
23
-
24
23
  import { HeadingLevel } from '../../../components/BaseHeading/BaseHeading.vue'
24
+ import { anchorizeStreamfield } from '../../../utils/anchorizeStreamfield'
25
25
 
26
26
  interface EduLessonSectionObject extends PageEduLessonSectionProps {
27
27
  type?: string
@@ -143,6 +143,10 @@ const sectionOrder = [
143
143
  'bottom'
144
144
  ]
145
145
 
146
+ const filteredBody = computed(() => {
147
+ return anchorizeStreamfield(data?.body) || []
148
+ })
149
+
146
150
  // mimic HeadingBlock data shape for defined section headings
147
151
  const staticSectionHeadings = computed((): { [key: string]: BlockHeadingObject } | undefined => {
148
152
  if (data) {
@@ -184,8 +188,9 @@ const keyedCustomSections = computed(
184
188
  if (!acc[position]) {
185
189
  acc[position] = []
186
190
  }
191
+ const filteredContent = anchorizeStreamfield(section.content) || []
187
192
  acc[position].push(section.heading)
188
- acc[position].push(...section.content)
193
+ acc[position].push(...filteredContent)
189
194
  return acc
190
195
  },
191
196
  {}
@@ -210,7 +215,8 @@ const consolidatedBlocks = computed(() => {
210
215
  blocks.push(staticSectionHeadings.value[section])
211
216
  }
212
217
  if (section !== 'materials' && section !== 'procedures') {
213
- blocks.push(...data[section])
218
+ const filteredBlocks = anchorizeStreamfield(data[section]) || []
219
+ blocks.push(...filteredBlocks)
214
220
  } else if (section === 'procedures' && data.procedures?.length) {
215
221
  // get blocks in nested procedures
216
222
  data.procedures.forEach((item) => {
@@ -230,8 +236,8 @@ const consolidatedBlocks = computed(() => {
230
236
  blocks.push(...keyedCustomSections.value['bottom'])
231
237
  }
232
238
  // include body blocks
233
- if (data?.body?.length) {
234
- blocks.push(...data.body)
239
+ if (filteredBody.value) {
240
+ blocks.push(...filteredBody.value)
235
241
  }
236
242
 
237
243
  return blocks
@@ -248,7 +254,10 @@ const consolidatedSections = computed((): EduLessonSectionObject[] => {
248
254
  if (data && data[section]) {
249
255
  sections.push({
250
256
  heading: staticSectionHeadings.value ? staticSectionHeadings.value[section] : undefined,
251
- blocks: section !== 'materials' && section !== 'procedures' ? data[section] : undefined,
257
+ blocks:
258
+ section !== 'materials' && section !== 'procedures'
259
+ ? anchorizeStreamfield(data[section])
260
+ : undefined,
252
261
  text: section === 'materials' ? data[section] : undefined,
253
262
  procedures: section === 'procedures' ? data[section] : undefined,
254
263
  image: data[`${section}Image`]
@@ -269,6 +278,7 @@ const consolidatedSections = computed((): EduLessonSectionObject[] => {
269
278
 
270
279
  return filteredSections
271
280
  })
281
+
272
282
  const computedClass = computed((): string => {
273
283
  if (heroTitle.value) {
274
284
  return '-nav-offset'
@@ -390,8 +400,8 @@ const computedClass = computed((): string => {
390
400
 
391
401
  <!-- streamfield blocks -->
392
402
  <BlockStreamfield
393
- v-if="data.body?.length"
394
- :data="data.body"
403
+ v-if="filteredBody?.length"
404
+ :data="filteredBody"
395
405
  />
396
406
 
397
407
  <!-- related links -->
@@ -11,6 +11,7 @@ import BlockText from './../../../components/BlockText/BlockText.vue'
11
11
  import BlockStreamfield from './../../../components/BlockStreamfield/BlockStreamfield.vue'
12
12
  import NavJumpMenu from './../../../components/NavJumpMenu/NavJumpMenu.vue'
13
13
  import AboutTheAuthor from './../../../components/AboutTheAuthor/AboutTheAuthor.vue'
14
+ import { anchorizeStreamfield } from './../../../utils/anchorizeStreamfield'
14
15
 
15
16
  interface PageEduNewsDetailObject extends PageObject {
16
17
  readTime: string
@@ -43,6 +44,11 @@ const heroInline = computed(() => {
43
44
  return false
44
45
  })
45
46
 
47
+ const filteredBody = computed(() => {
48
+ // adds anchors to headings within RichTextBlock
49
+ return anchorizeStreamfield(props.data?.body)
50
+ })
51
+
46
52
  const computedClass = computed(() => {
47
53
  if (heroInline.value || heroEmpty.value) {
48
54
  return 'pt-5 lg:pt-12'
@@ -72,7 +78,7 @@ defineExpose({
72
78
  v-if="data.showJumpMenu"
73
79
  ref="PageEduNewsDetailJumpMenu"
74
80
  :title="data.title"
75
- :blocks="data.body"
81
+ :blocks="filteredBody"
76
82
  dropdown-text="In this news article"
77
83
  />
78
84
 
@@ -150,7 +156,7 @@ defineExpose({
150
156
  <!-- streamfield blocks -->
151
157
  <BlockStreamfield
152
158
  itemprop="articleBody"
153
- :data="data.body"
159
+ :data="filteredBody"
154
160
  />
155
161
 
156
162
  <LayoutHelper
@@ -24,9 +24,9 @@ import PageEduStudentProjectSection, {
24
24
  import NavJumpMenu from './../../../components/NavJumpMenu/NavJumpMenu.vue'
25
25
  import HeroInlineMedia from './../../../components/HeroInlineMedia/HeroInlineMedia.vue'
26
26
  import AboutTheAuthor from './../../../components/AboutTheAuthor/AboutTheAuthor.vue'
27
-
28
27
  import { HeadingLevel } from '../../../components/BaseHeading/BaseHeading.vue'
29
28
  import StudentProjectBadge from '@explorer-1/common/src/images/svg/student-project-badge.svg'
29
+
30
30
  const route = useRoute()
31
31
  interface EduStudentProjectSectionObject extends PageEduStudentProjectSectionProps {
32
32
  type?: string
@@ -13,6 +13,7 @@ import BlockRelatedLinks from '../../../components/BlockRelatedLinks/BlockRelate
13
13
  import NavJumpMenu from './../../../components/NavJumpMenu/NavJumpMenu.vue'
14
14
  import HeroInlineMedia from './../../../components/HeroInlineMedia/HeroInlineMedia.vue'
15
15
  import AboutTheAuthor from './../../../components/AboutTheAuthor/AboutTheAuthor.vue'
16
+ import { anchorizeStreamfield } from './../../../utils/anchorizeStreamfield'
16
17
 
17
18
  interface PageEduTeachableMomentProps {
18
19
  data?: PageEduResourcesObject
@@ -68,6 +69,11 @@ const heroInline = computed((): boolean => {
68
69
  return false
69
70
  })
70
71
 
72
+ const filteredBody = computed(() => {
73
+ // adds anchors to headings within RichTextBlock
74
+ return anchorizeStreamfield(data?.body)
75
+ })
76
+
71
77
  const computedClass = computed((): string => {
72
78
  if (heroInline.value || heroEmpty.value) {
73
79
  return 'pt-5 lg:pt-12'
@@ -87,7 +93,7 @@ const computedClass = computed((): string => {
87
93
  v-if="data.showJumpMenu"
88
94
  ref="PageEduTeachableMomentJumpMenu"
89
95
  :title="data.title"
90
- :blocks="data.body"
96
+ :blocks="filteredBody"
91
97
  dropdown-text="In this Teachable Moment"
92
98
  />
93
99
 
@@ -160,7 +166,7 @@ const computedClass = computed((): string => {
160
166
  </LayoutHelper>
161
167
 
162
168
  <!-- streamfield blocks -->
163
- <BlockStreamfield :data="data.body" />
169
+ <BlockStreamfield :data="filteredBody" />
164
170
 
165
171
  <!-- related links -->
166
172
  <LayoutHelper
@@ -0,0 +1,20 @@
1
+ import type { BlockTextObject } from './../components/BlockText/BlockText.vue'
2
+ import { getHeadingId } from './getHeadingId'
3
+
4
+ export const anchorizeBlock = (block: BlockTextObject, headingLevel = 'h2') => {
5
+ if (block?.blockType === 'RichTextBlock') {
6
+ const regex = new RegExp(`<${headingLevel} data-block-key="(.*?)">(.*?)</${headingLevel}>`, 'g')
7
+ let text = block?.value
8
+ if (text) {
9
+ text = text.replaceAll(regex, (_match, g1, g2) => {
10
+ const headingId = getHeadingId(g2, g1)
11
+ return `<${headingLevel} id="${headingId}">${g2}</${headingLevel}>`
12
+ })
13
+ }
14
+ return {
15
+ ...block,
16
+ value: text
17
+ }
18
+ }
19
+ return block
20
+ }
@@ -0,0 +1,15 @@
1
+ import { anchorizeBlock } from './anchorizeBlock'
2
+ import { StreamfieldBlockData } from '../interfaces'
3
+ export const anchorizeStreamfield = (blocks?: StreamfieldBlockData[], headingLevel = 'h2') => {
4
+ if (blocks?.length) {
5
+ // @ts-expect-error
6
+ const filteredBlocks = []
7
+ blocks.forEach((block) => {
8
+ // @ts-expect-error
9
+ filteredBlocks.push(anchorizeBlock(block, headingLevel))
10
+ })
11
+ // @ts-expect-error
12
+ return filteredBlocks
13
+ }
14
+ return blocks
15
+ }