@cooperco/cooper-component-library 0.1.121 → 0.1.122

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/dist/cms/0090-splitmodule-flat-fields.cjs +114 -0
  2. package/dist/cms/0091-splitmodule-migrate-data.cjs +73 -0
  3. package/dist/cms/0092-splitmodule-collection-constraints.cjs +88 -0
  4. package/dist/cms/0093-splitmodule-bodycopy-no-embeds.cjs +57 -0
  5. package/dist/cms/containerCollectionModule.query.ts +0 -6
  6. package/dist/cms/contentful/migrations/scripts/0090-splitmodule-flat-fields.cjs +114 -0
  7. package/dist/cms/contentful/migrations/scripts/0091-splitmodule-migrate-data.cjs +73 -0
  8. package/dist/cms/contentful/migrations/scripts/0092-splitmodule-collection-constraints.cjs +88 -0
  9. package/dist/cms/contentful/migrations/scripts/0093-splitmodule-bodycopy-no-embeds.cjs +57 -0
  10. package/dist/cms/contentful/queries/containerCollectionModule.query.js +0 -6
  11. package/dist/cms/contentful/queries/containerCollectionModule.query.ts +0 -6
  12. package/dist/cms/contentful/queries/page.query.js +0 -5
  13. package/dist/cms/contentful/queries/page.query.ts +0 -5
  14. package/dist/cms/contentful/queries/splitModule.query.js +30 -56
  15. package/dist/cms/contentful/queries/splitModule.query.ts +30 -56
  16. package/dist/cms/migrations/scripts/0090-splitmodule-flat-fields.cjs +114 -0
  17. package/dist/cms/migrations/scripts/0091-splitmodule-migrate-data.cjs +73 -0
  18. package/dist/cms/migrations/scripts/0092-splitmodule-collection-constraints.cjs +88 -0
  19. package/dist/cms/migrations/scripts/0093-splitmodule-bodycopy-no-embeds.cjs +57 -0
  20. package/dist/cms/page.query.ts +0 -5
  21. package/dist/cms/queries/containerCollectionModule.query.ts +0 -6
  22. package/dist/cms/queries/page.query.ts +0 -5
  23. package/dist/cms/queries/splitModule.query.ts +30 -56
  24. package/dist/cms/scripts/0090-splitmodule-flat-fields.cjs +114 -0
  25. package/dist/cms/scripts/0091-splitmodule-migrate-data.cjs +73 -0
  26. package/dist/cms/scripts/0092-splitmodule-collection-constraints.cjs +88 -0
  27. package/dist/cms/scripts/0093-splitmodule-bodycopy-no-embeds.cjs +57 -0
  28. package/dist/cms/splitModule.query.ts +30 -56
  29. package/dist/lib/component-lib.js +2656 -2595
  30. package/dist/lib/component-lib.umd.cjs +23 -23
  31. package/dist/lib/css/main.css +12 -0
  32. package/dist/lib/style.css +1 -1
  33. package/dist/types/src/components/ContainerCollectionModule/ContainerCollectionModule.d.ts +2 -2
  34. package/dist/types/src/components/ContainerModule/ContainerModule.d.ts +0 -1
  35. package/dist/types/src/components/SplitModule/SplitModule.d.ts +12 -11
  36. package/dist/types/src/config/defaultPassthrough/types.d.ts +3 -1
  37. package/package.json +1 -1
@@ -1,79 +1,53 @@
1
1
  import { gql } from 'graphql-tag'
2
2
  import type { DocumentNode } from 'graphql'
3
+ import { imageFragment } from './fragments.js'
3
4
 
4
5
  export const getSplitModule: DocumentNode = gql`
6
+ ${imageFragment}
5
7
  query splitModuleQuery($id: String!, $preview: Boolean = false) {
6
8
  splitModule(id: $id, preview: $preview) {
7
9
  sys {
8
10
  id
9
11
  }
10
12
 
11
- start {
12
- __typename
13
-
14
- ... on ContentModule {
15
- sys {
16
- id
17
- }
18
- }
19
-
20
- ... on Image {
21
- sys {
22
- id
23
- }
24
- }
25
-
26
- ... on Video {
27
- sys {
28
- id
29
- }
30
- }
13
+ image {
14
+ ...imageFragment
31
15
  }
32
16
 
33
- center {
34
- __typename
35
-
36
- ... on ContentModule {
37
- sys {
38
- id
39
- }
40
- }
41
-
42
- ... on Image {
43
- sys {
44
- id
45
- }
46
- }
47
-
48
- ... on Video {
49
- sys {
50
- id
17
+ header {
18
+ json
19
+ links {
20
+ entries {
21
+ inline {
22
+ sys {
23
+ id
24
+ }
25
+ ... on HighlightedText {
26
+ text
27
+ }
28
+ }
51
29
  }
52
30
  }
53
31
  }
54
32
 
55
- end {
56
- __typename
57
-
58
- ... on ContentModule {
59
- sys {
60
- id
61
- }
62
- }
63
-
64
- ... on Image {
65
- sys {
66
- id
67
- }
68
- }
69
-
70
- ... on Video {
71
- sys {
72
- id
33
+ bodyCopy {
34
+ json
35
+ links {
36
+ entries {
37
+ inline {
38
+ sys {
39
+ id
40
+ }
41
+ ... on HighlightedText {
42
+ text
43
+ }
44
+ }
73
45
  }
74
46
  }
75
47
  }
76
48
 
49
+ variant
50
+
77
51
  backgroundColor
78
52
  }
79
53
  }
@@ -0,0 +1,114 @@
1
+ module.exports = {
2
+ // @ts-check
3
+ /** @type { import('contentful-migration').MigrationFunction } */
4
+ up: function (migration) {
5
+ const splitModule = migration.editContentType('splitModule')
6
+
7
+ splitModule
8
+ .createField('image')
9
+ .name('Image')
10
+ .type('Link')
11
+ .linkType('Entry')
12
+ .required(false)
13
+ .validations([{ linkContentType: ['image'] }])
14
+
15
+ // header / bodyCopy are RichText mirroring contentModule.headline /
16
+ // contentModule.bodyCopy (verified on qa-2026-07-01) so the existing
17
+ // rich-text documents — bold marks, embedded highlightedText numbers
18
+ // ("80+"), footnotes — copy over losslessly and the consumer renders
19
+ // them the same way it renders contentModule today. Localized to match
20
+ // the source fields (en-US, es, ru, zh).
21
+ splitModule
22
+ .createField('header')
23
+ .name('Header')
24
+ .type('RichText')
25
+ .localized(true)
26
+ .required(false)
27
+ .validations([
28
+ {
29
+ enabledMarks: ['bold', 'italic', 'underline'],
30
+ message: 'Only bold, italic, and underline marks are allowed',
31
+ },
32
+ {
33
+ enabledNodeTypes: [
34
+ 'ordered-list',
35
+ 'unordered-list',
36
+ 'hr',
37
+ 'hyperlink',
38
+ 'embedded-entry-inline',
39
+ ],
40
+ },
41
+ {
42
+ nodes: {
43
+ 'embedded-entry-inline': [
44
+ {
45
+ linkContentType: ['highlightedText'],
46
+ message: 'You can only embed Highlighted Text.',
47
+ },
48
+ ],
49
+ },
50
+ },
51
+ ])
52
+
53
+ splitModule
54
+ .createField('bodyCopy')
55
+ .name('Body Copy')
56
+ .type('RichText')
57
+ .localized(true)
58
+ .required(false)
59
+ .validations([
60
+ {
61
+ enabledMarks: ['bold', 'italic', 'underline'],
62
+ message: 'Only bold, italic, and underline marks are allowed',
63
+ },
64
+ {
65
+ enabledNodeTypes: [
66
+ 'ordered-list',
67
+ 'unordered-list',
68
+ 'hr',
69
+ 'hyperlink',
70
+ 'embedded-entry-inline',
71
+ 'table',
72
+ ],
73
+ },
74
+ {
75
+ nodes: {
76
+ 'embedded-entry-inline': [
77
+ {
78
+ linkContentType: ['testimonialModule'],
79
+ message: 'You can embed Testimonial entries.',
80
+ },
81
+ ],
82
+ },
83
+ },
84
+ ])
85
+
86
+ splitModule
87
+ .createField('variant')
88
+ .name('Variant')
89
+ .type('Symbol')
90
+ .required(true)
91
+ .validations([
92
+ { in: ['2 Section', '3 Section', 'Background Image'] },
93
+ ])
94
+
95
+ splitModule.changeFieldControl('variant', 'builtin', 'dropdown')
96
+
97
+ // Order the new fields after entryName using the proven beforeField form
98
+ // (afterField is avoided — every existing migration here uses beforeField,
99
+ // and field ordering is cosmetic, not worth risking a migration abort).
100
+ splitModule.moveField('variant').beforeField('backgroundColor')
101
+ splitModule.moveField('bodyCopy').beforeField('variant')
102
+ splitModule.moveField('header').beforeField('bodyCopy')
103
+ splitModule.moveField('image').beforeField('header')
104
+ },
105
+
106
+ /** @type { import('contentful-migration').MigrationFunction } */
107
+ down: function (migration) {
108
+ const splitModule = migration.editContentType('splitModule')
109
+ splitModule.deleteField('image')
110
+ splitModule.deleteField('header')
111
+ splitModule.deleteField('bodyCopy')
112
+ splitModule.deleteField('variant')
113
+ },
114
+ }
@@ -0,0 +1,73 @@
1
+ // Schema migration for splitModule: remove the old slot fields now that the
2
+ // flat fields (image/header/bodyCopy/variant) were added in 0090.
3
+ //
4
+ // VERIFIED against qa-2026-07-01 (via Contentful MCP):
5
+ // - splitModule fields are: entryName, start, center, end, backgroundImage,
6
+ // backgroundColor. There is NO `headline` field (do not deleteField it —
7
+ // that would abort the migration).
8
+ //
9
+ // DATA HANDLING: this is a MODEL-ONLY migration. The plan is to DELETE all
10
+ // existing splitModule entries BEFORE running these migrations, then re-author
11
+ // them by hand against the new schema. With zero entries present, deleting
12
+ // start/center/end/backgroundImage affects only the content type — there is no
13
+ // entry data to lose or migrate. (If entries still existed, deleting these
14
+ // fields would drop their slot content.)
15
+ //
16
+ // Because there is no data step, migrations run linearly: 0090 -> 0091 -> 0092.
17
+
18
+ module.exports = {
19
+ // @ts-check
20
+ /** @type { import('contentful-migration').MigrationFunction } */
21
+ up: function (migration) {
22
+ const splitModule = migration.editContentType('splitModule')
23
+ // NOTE: the live splitModule type has NO `headline` field (verified on
24
+ // qa-2026-07-01: fields are entryName, start, center, end,
25
+ // backgroundImage, backgroundColor). Only delete fields that exist —
26
+ // deleting a non-existent field aborts the whole migration.
27
+ splitModule.deleteField('start')
28
+ splitModule.deleteField('center')
29
+ splitModule.deleteField('end')
30
+ splitModule.deleteField('backgroundImage')
31
+ },
32
+
33
+ /** @type { import('contentful-migration').MigrationFunction } */
34
+ down: function (migration) {
35
+ const splitModule = migration.editContentType('splitModule')
36
+
37
+ const slotValidations = [
38
+ { linkContentType: ['image', 'video', 'contentModule'] },
39
+ ]
40
+
41
+ splitModule
42
+ .createField('start')
43
+ .name('Start')
44
+ .type('Link')
45
+ .linkType('Entry')
46
+ .required(false)
47
+ .validations(slotValidations)
48
+
49
+ splitModule
50
+ .createField('center')
51
+ .name('Center')
52
+ .type('Link')
53
+ .linkType('Entry')
54
+ .required(false)
55
+ .validations(slotValidations)
56
+
57
+ splitModule
58
+ .createField('end')
59
+ .name('End')
60
+ .type('Link')
61
+ .linkType('Entry')
62
+ .required(false)
63
+ .validations(slotValidations)
64
+
65
+ splitModule
66
+ .createField('backgroundImage')
67
+ .name('Background Image')
68
+ .type('Link')
69
+ .linkType('Entry')
70
+ .required(false)
71
+ .validations([{ linkContentType: ['image'] }])
72
+ },
73
+ }
@@ -0,0 +1,88 @@
1
+ // Collection + page constraints for the SplitModule consolidation.
2
+ //
3
+ // 1. Restrict containerCollectionModule.modules to splitModule only (it no
4
+ // longer accepts containerModule). The content-type id / __typename are
5
+ // unchanged. NOTE: the display-name change below is optional — remove the
6
+ // collection.name(...) lines if you want to keep the "Container Collection
7
+ // Module" label. The Vue component keeps the ContainerCollectionModule name.
8
+ // 2. Remove splitModule from page.pageModules — SplitModule is collection-only
9
+ // and must not be droppable directly onto a page.
10
+ //
11
+ // MANUAL STEP (not automatable in this migration — cross-type entry change):
12
+ // The "50,000+ transplants" row is currently a containerModule entry. Convert
13
+ // it to a splitModule entry with variant 'Background Image' (header/bodyCopy
14
+ // copied over, backgroundImage -> image incl. mobileMedia), then swap the
15
+ // reference inside the collection's modules list. Leave the old containerModule
16
+ // entry unpublished (do not delete) so `down` can restore it. Do this AFTER
17
+ // 0090/0091 have run and BEFORE relying on the collection rendering only
18
+ // SplitModules.
19
+
20
+ module.exports = {
21
+ // @ts-check
22
+ /** @type { import('contentful-migration').MigrationFunction } */
23
+ up: function (migration) {
24
+ const collection = migration.editContentType('containerCollectionModule')
25
+ collection.editField('modules').items({
26
+ type: 'Link',
27
+ linkType: 'Entry',
28
+ validations: [{ linkContentType: ['splitModule'] }],
29
+ })
30
+
31
+ const page = migration.editContentType('page')
32
+ page.editField('pageModules').items({
33
+ type: 'Link',
34
+ linkType: 'Entry',
35
+ validations: [
36
+ {
37
+ linkContentType: [
38
+ 'carouselModule',
39
+ 'chartModule',
40
+ 'containerCollectionModule',
41
+ 'containerModule',
42
+ 'contentModule',
43
+ 'logoCollectionModule',
44
+ 'placeholderModule',
45
+ 'productModule',
46
+ 'tabModule',
47
+ 'testimonialModule',
48
+ 'tileCollectionModule',
49
+ ],
50
+ },
51
+ ],
52
+ })
53
+ },
54
+
55
+ /** @type { import('contentful-migration').MigrationFunction } */
56
+ down: function (migration) {
57
+ const collection = migration.editContentType('containerCollectionModule')
58
+ collection.editField('modules').items({
59
+ type: 'Link',
60
+ linkType: 'Entry',
61
+ validations: [{ linkContentType: ['containerModule', 'splitModule'] }],
62
+ })
63
+
64
+ const page = migration.editContentType('page')
65
+ page.editField('pageModules').items({
66
+ type: 'Link',
67
+ linkType: 'Entry',
68
+ validations: [
69
+ {
70
+ linkContentType: [
71
+ 'carouselModule',
72
+ 'chartModule',
73
+ 'containerCollectionModule',
74
+ 'containerModule',
75
+ 'contentModule',
76
+ 'logoCollectionModule',
77
+ 'placeholderModule',
78
+ 'productModule',
79
+ 'splitModule',
80
+ 'tabModule',
81
+ 'testimonialModule',
82
+ 'tileCollectionModule',
83
+ ],
84
+ },
85
+ ],
86
+ })
87
+ },
88
+ }
@@ -0,0 +1,57 @@
1
+ // Remove inline entry embeds from splitModule.bodyCopy.
2
+ //
3
+ // 0090 created bodyCopy allowing embedded-entry-inline (testimonialModule),
4
+ // mirroring contentModule. SplitModule does not render embedded entries, so
5
+ // this drops embedded-entry-inline from the allowed node types and removes the
6
+ // per-node testimonialModule validation. Plain rich text (bold/italic/lists/
7
+ // hyperlinks/table) is retained. `down` restores the original embed support.
8
+
9
+ module.exports = {
10
+ // @ts-check
11
+ /** @type { import('contentful-migration').MigrationFunction } */
12
+ up: function (migration) {
13
+ const splitModule = migration.editContentType('splitModule')
14
+
15
+ splitModule.editField('bodyCopy').validations([
16
+ {
17
+ enabledMarks: ['bold', 'italic', 'underline'],
18
+ message: 'Only bold, italic, and underline marks are allowed',
19
+ },
20
+ {
21
+ enabledNodeTypes: ['ordered-list', 'unordered-list', 'hr', 'hyperlink', 'table'],
22
+ },
23
+ ])
24
+ },
25
+
26
+ /** @type { import('contentful-migration').MigrationFunction } */
27
+ down: function (migration) {
28
+ const splitModule = migration.editContentType('splitModule')
29
+
30
+ splitModule.editField('bodyCopy').validations([
31
+ {
32
+ enabledMarks: ['bold', 'italic', 'underline'],
33
+ message: 'Only bold, italic, and underline marks are allowed',
34
+ },
35
+ {
36
+ enabledNodeTypes: [
37
+ 'ordered-list',
38
+ 'unordered-list',
39
+ 'hr',
40
+ 'hyperlink',
41
+ 'embedded-entry-inline',
42
+ 'table',
43
+ ],
44
+ },
45
+ {
46
+ nodes: {
47
+ 'embedded-entry-inline': [
48
+ {
49
+ linkContentType: ['testimonialModule'],
50
+ message: 'You can embed Testimonial entries.',
51
+ },
52
+ ],
53
+ },
54
+ },
55
+ ])
56
+ },
57
+ }
@@ -1,79 +1,53 @@
1
1
  import { gql } from 'graphql-tag'
2
2
  import type { DocumentNode } from 'graphql'
3
+ import { imageFragment } from './fragments.js'
3
4
 
4
5
  export const getSplitModule: DocumentNode = gql`
6
+ ${imageFragment}
5
7
  query splitModuleQuery($id: String!, $preview: Boolean = false) {
6
8
  splitModule(id: $id, preview: $preview) {
7
9
  sys {
8
10
  id
9
11
  }
10
12
 
11
- start {
12
- __typename
13
-
14
- ... on ContentModule {
15
- sys {
16
- id
17
- }
18
- }
19
-
20
- ... on Image {
21
- sys {
22
- id
23
- }
24
- }
25
-
26
- ... on Video {
27
- sys {
28
- id
29
- }
30
- }
13
+ image {
14
+ ...imageFragment
31
15
  }
32
16
 
33
- center {
34
- __typename
35
-
36
- ... on ContentModule {
37
- sys {
38
- id
39
- }
40
- }
41
-
42
- ... on Image {
43
- sys {
44
- id
45
- }
46
- }
47
-
48
- ... on Video {
49
- sys {
50
- id
17
+ header {
18
+ json
19
+ links {
20
+ entries {
21
+ inline {
22
+ sys {
23
+ id
24
+ }
25
+ ... on HighlightedText {
26
+ text
27
+ }
28
+ }
51
29
  }
52
30
  }
53
31
  }
54
32
 
55
- end {
56
- __typename
57
-
58
- ... on ContentModule {
59
- sys {
60
- id
61
- }
62
- }
63
-
64
- ... on Image {
65
- sys {
66
- id
67
- }
68
- }
69
-
70
- ... on Video {
71
- sys {
72
- id
33
+ bodyCopy {
34
+ json
35
+ links {
36
+ entries {
37
+ inline {
38
+ sys {
39
+ id
40
+ }
41
+ ... on HighlightedText {
42
+ text
43
+ }
44
+ }
73
45
  }
74
46
  }
75
47
  }
76
48
 
49
+ variant
50
+
77
51
  backgroundColor
78
52
  }
79
53
  }