@cntrl-site/sdk-nextjs 0.2.13 → 0.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.
Files changed (36) hide show
  1. package/.idea/inspectionProfiles/Project_Default.xml +15 -0
  2. package/lib/components/Article.js +2 -2
  3. package/lib/components/Item.js +4 -2
  4. package/lib/components/Page.js +4 -1
  5. package/lib/components/Section.js +3 -1
  6. package/lib/components/items/ImageItem.js +5 -1
  7. package/lib/components/items/RectangleItem.js +5 -1
  8. package/lib/components/items/RichTextItem.js +12 -4
  9. package/lib/components/items/VideoItem.js +26 -22
  10. package/lib/components/items/VimeoEmbed.js +3 -1
  11. package/lib/components/items/YoutubeEmbed.js +3 -1
  12. package/lib/index.js +4 -4
  13. package/lib/provider/CntrlSdkContext.js +7 -0
  14. package/lib/utils/{RichTextConverter.js → RichTextConverter/RichTextConverter.js} +3 -3
  15. package/lib/utils/generateTypePresetStyles/generateTypePresetStyles.js +27 -0
  16. package/package.json +5 -2
  17. package/src/components/Article.tsx +4 -5
  18. package/src/components/Item.tsx +4 -4
  19. package/src/components/Page.tsx +7 -1
  20. package/src/components/Section.tsx +4 -3
  21. package/src/components/items/ImageItem.tsx +15 -11
  22. package/src/components/items/RectangleItem.tsx +12 -8
  23. package/src/components/items/RichTextItem.tsx +22 -11
  24. package/src/components/items/VideoItem.tsx +31 -29
  25. package/src/components/items/VimeoEmbed.tsx +4 -2
  26. package/src/components/items/YoutubeEmbed.tsx +3 -1
  27. package/src/index.ts +2 -3
  28. package/src/provider/CntrlSdkContext.ts +13 -2
  29. package/src/utils/{RichTextConverter.tsx → RichTextConverter/RichTextConverter.tsx} +7 -6
  30. package/src/utils/generateTypePresetStyles/__mock__/layoutsMock.ts +37 -0
  31. package/src/utils/generateTypePresetStyles/__mock__/presetMock.ts +49 -0
  32. package/src/utils/generateTypePresetStyles/generateTypePresetStyles.test.ts +49 -0
  33. package/src/utils/generateTypePresetStyles/generateTypePresetStyles.ts +25 -0
  34. package/src/utils/getInvertedRanges.ts +43 -0
  35. package/.idea/workspace.xml +0 -293
  36. package/cntrl-site-sdk-nextjs-0.2.13.tgz +0 -0
@@ -3,39 +3,41 @@ import { TVideoItem } from '@cntrl-site/sdk';
3
3
  import { ItemProps } from '../Item';
4
4
  import { LinkWrapper } from '../LinkWrapper';
5
5
  import { getLayoutStyles } from '@cntrl-site/sdk';
6
+ import { useCntrlContext } from '../../provider/useCntrlContext';
6
7
 
7
- export const VideoItem: FC<ItemProps<TVideoItem>> = ({ item, layouts }) => (
8
- <LinkWrapper url={item.link?.url}>
9
- <>
8
+ export const VideoItem: FC<ItemProps<TVideoItem>> = ({ item }) => {
9
+ const { layouts } = useCntrlContext();
10
+ return (
11
+ <LinkWrapper url={item.link?.url}>
10
12
  <div className={`video-wrapper-${item.id}`}>
11
13
  <video autoPlay muted loop playsInline className="video">
12
14
  <source src={item.commonParams.url} />
13
15
  </video>
14
16
  </div>
15
17
  <style jsx>{`
16
- ${getLayoutStyles(layouts, [item.layoutParams], ([{ strokeColor, radius, strokeWidth, opacity }]) => (`
17
- .video-wrapper-${item.id} {
18
- position: absolute;
19
- overflow: hidden;
20
- width: 100%;
21
- height: 100%;
22
- border-style: solid;
23
- box-sizing: border-box;
24
- border-color: ${strokeColor};
25
- border-radius: ${radius * 100}vw;
26
- border-width: ${strokeWidth * 100}vw;
27
- opacity: ${opacity};
28
- }`
29
- ))
30
- }
31
- .video {
32
- width: 100%;
33
- height: 100%;
34
- opacity: 1;
35
- object-fit: cover;
36
- pointer-events: none;
37
- }
38
- `}</style>
39
- </>
40
- </LinkWrapper>
41
- );
18
+ ${getLayoutStyles(layouts, [item.layoutParams], ([{ strokeColor, radius, strokeWidth, opacity }]) => (`
19
+ .video-wrapper-${item.id} {
20
+ position: absolute;
21
+ overflow: hidden;
22
+ width: 100%;
23
+ height: 100%;
24
+ border-style: solid;
25
+ box-sizing: border-box;
26
+ border-color: ${strokeColor};
27
+ border-radius: ${radius * 100}vw;
28
+ border-width: ${strokeWidth * 100}vw;
29
+ opacity: ${opacity};
30
+ }`
31
+ ))
32
+ }
33
+ .video {
34
+ width: 100%;
35
+ height: 100%;
36
+ opacity: 1;
37
+ object-fit: cover;
38
+ pointer-events: none;
39
+ }
40
+ `}</style>
41
+ </LinkWrapper>
42
+ );
43
+ };
@@ -3,8 +3,10 @@ import { getLayoutStyles } from '@cntrl-site/sdk';
3
3
  import { TVimeoEmbedItem } from '@cntrl-site/core';
4
4
  import { ItemProps } from '../Item';
5
5
  import { LinkWrapper } from '../LinkWrapper';
6
+ import { useCntrlContext } from '../../provider/useCntrlContext';
6
7
 
7
- export const VimeoEmbedItem: FC<ItemProps<TVimeoEmbedItem>> = ({ item, layouts }) => {
8
+ export const VimeoEmbedItem: FC<ItemProps<TVimeoEmbedItem>> = ({ item }) => {
9
+ const { layouts } = useCntrlContext();
8
10
  const { autoplay, controls, loop, muted, pictureInPicture, url } = item.commonParams;
9
11
  const getValidVimeoUrl = (url: string): string => {
10
12
  const validURL = new URL(url);
@@ -53,5 +55,5 @@ export const VimeoEmbedItem: FC<ItemProps<TVimeoEmbedItem>> = ({ item, layouts }
53
55
  }
54
56
  `}</style>
55
57
  </LinkWrapper>
56
- )
58
+ );
57
59
  };
@@ -4,8 +4,10 @@ import { TYoutubeEmbedItem } from '@cntrl-site/core';
4
4
  import { ItemProps } from '../Item';
5
5
  import { LinkWrapper } from '../LinkWrapper';
6
6
  import { getYoutubeId } from '../../utils/getValidYoutubeUrl';
7
+ import { useCntrlContext } from '../../provider/useCntrlContext';
7
8
 
8
- export const YoutubeEmbedItem: FC<ItemProps<TYoutubeEmbedItem>> = ({ item, layouts }) => {
9
+ export const YoutubeEmbedItem: FC<ItemProps<TYoutubeEmbedItem>> = ({ item }) => {
10
+ const { layouts } = useCntrlContext();
9
11
  const { autoplay, controls, url } = item.commonParams;
10
12
 
11
13
  const getValidYoutubeUrl = (url: string): string => {
package/src/index.ts CHANGED
@@ -1,8 +1,8 @@
1
- import { cntrlSdkContext } from './provider/defaultContext';
1
+ export { cntrlSdkContext } from './provider/defaultContext';
2
2
 
3
3
  export * from '@cntrl-site/sdk';
4
4
 
5
- export { RichTextConverter } from './utils/RichTextConverter';
5
+ export { RichTextConverter } from './utils/RichTextConverter/RichTextConverter';
6
6
  export { Page } from './components/Page';
7
7
  export { CNTRLHead as Head } from './components/Head';
8
8
  export { Article } from './components/Article';
@@ -19,4 +19,3 @@ export { YoutubeEmbedItem } from './components/items/YoutubeEmbed';
19
19
  // custom items
20
20
  export { CntrlProvider } from './provider/CntrlProvider';
21
21
  export type { CustomItemComponent } from './provider/CustomItemTypes';
22
- export const CustomItems = cntrlSdkContext.customItems;
@@ -1,7 +1,18 @@
1
1
  import { CustomItemRegistry } from './CustomItemRegistry';
2
+ import { TLayout, TTypePresets } from '@cntrl-site/sdk';
2
3
 
3
4
  export class CntrlSdkContext {
5
+ public typePresets?: TTypePresets;
6
+ public layouts: TLayout[] = [];
4
7
  constructor(
5
- public readonly customItems: CustomItemRegistry
6
- ) { }
8
+ public readonly customItems: CustomItemRegistry,
9
+ ) {}
10
+
11
+ setTypePresets(typePresets: TTypePresets) {
12
+ this.typePresets = typePresets;
13
+ }
14
+
15
+ setLayouts(layouts: TLayout[]) {
16
+ this.layouts = layouts;
17
+ }
7
18
  }
@@ -7,12 +7,12 @@ import {
7
7
  TRichTextItem,
8
8
  VerticalAlign
9
9
  } from '@cntrl-site/sdk';
10
- import { LinkWrapper } from '../components/LinkWrapper';
10
+ import { LinkWrapper } from '../../components/LinkWrapper';
11
11
 
12
12
  interface StyleGroup {
13
13
  start: number;
14
14
  end: number;
15
- styles: DraftStyle[];
15
+ styles: Style[];
16
16
  }
17
17
 
18
18
  interface EntitiesGroup {
@@ -22,7 +22,7 @@ interface EntitiesGroup {
22
22
  end: number;
23
23
  }
24
24
 
25
- interface DraftStyle {
25
+ interface Style {
26
26
  name: string;
27
27
  value?: string;
28
28
  }
@@ -36,7 +36,8 @@ export const FontStyles: Record<string, Record<string, string>> = {
36
36
  export class RichTextConverter {
37
37
  toHtml(
38
38
  richText: TRichTextItem,
39
- layouts: TLayout[]
39
+ layouts: TLayout[],
40
+ hasPreset: boolean
40
41
  ): [ReactNode[], string] {
41
42
  const { text: rawText, blocks = [] } = richText.commonParams;
42
43
  const text = Array.from(rawText); // because of emoji
@@ -86,7 +87,7 @@ export class RichTextConverter {
86
87
  .${blockClass} {
87
88
  display: ${group.some(g => g.layout === l.id) ? 'block' : 'none'};
88
89
  text-align: ${ta};
89
- line-height: 0;
90
+ ${hasPreset ? '' : 'line-height: 0;'}
90
91
  white-space: normal;
91
92
  overflow-wrap: break-word;
92
93
  }
@@ -215,7 +216,7 @@ export class RichTextConverter {
215
216
  return entitiesGroups;
216
217
  }
217
218
 
218
- private static fromDraftToInline(draftStyle: DraftStyle): string {
219
+ private static fromDraftToInline(draftStyle: Style): string {
219
220
  const { value, name } = draftStyle;
220
221
  const map: Record<string, Record<string, string | undefined>> = {
221
222
  'COLOR': { 'color': value },
@@ -0,0 +1,37 @@
1
+ import { TLayout } from '@cntrl-site/sdk';
2
+
3
+ const sampleGrid = {
4
+ columnsAmount: 0,
5
+ beatHeight: 0,
6
+ beatMultiplier: 1,
7
+ maxWidth: 0,
8
+ columnWidth: 0.01,
9
+ gutterWidth: 0.001
10
+ };
11
+
12
+ export const layoutsMock: TLayout[] = [
13
+ {
14
+ id: 'tablet',
15
+ exemplary: 768,
16
+ startsWith: 768,
17
+ title: 'Tablet',
18
+ icon: 'any',
19
+ grid: sampleGrid
20
+ },
21
+ {
22
+ id: 'desktop',
23
+ exemplary: 1440,
24
+ startsWith: 1024,
25
+ title: 'Desktop',
26
+ icon: 'any',
27
+ grid: sampleGrid
28
+ },
29
+ {
30
+ id: 'mobile',
31
+ exemplary: 375,
32
+ startsWith: 0,
33
+ title: 'Mobile',
34
+ icon: 'any',
35
+ grid: sampleGrid
36
+ }
37
+ ];
@@ -0,0 +1,49 @@
1
+ import { AllowedTags, TTypePresets } from '@cntrl-site/sdk';
2
+
3
+ const layoutParams = {
4
+ 'desktop': {
5
+ fontSize: 0.011111,
6
+ lineHeight: 0.013888,
7
+ wordSpacing: 0.0006944,
8
+ letterSpacing: 0.0006944,
9
+ color: 'rgba(0, 0, 0, 1)'
10
+ },
11
+ 'tablet': {
12
+ fontSize: 0.02604,
13
+ lineHeight: 0.03125,
14
+ wordSpacing: 0,
15
+ letterSpacing: 0,
16
+ color: 'rgba(0, 0, 0, 1)'
17
+ },
18
+ 'mobile': {
19
+ fontSize: 0.053333,
20
+ lineHeight: 0.064,
21
+ wordSpacing: 0.008,
22
+ letterSpacing: 0.008,
23
+ color: 'rgba(0, 0, 0, 1)'
24
+ }
25
+ };
26
+
27
+ export const presetMock: TTypePresets = {
28
+ id: 'presetId',
29
+ presets: [
30
+ {
31
+ id: 'heading01',
32
+ fontFamily: 'Aeonik',
33
+ fontWeight: '400',
34
+ fontStyle: '',
35
+ name: 'Heading',
36
+ tag: AllowedTags.h1,
37
+ layoutParams
38
+ },
39
+ {
40
+ id: 'heading02',
41
+ fontFamily: 'Aeonik',
42
+ fontWeight: '400',
43
+ fontStyle: 'italic',
44
+ name: 'Heading',
45
+ tag: AllowedTags.h1,
46
+ layoutParams
47
+ }
48
+ ]
49
+ };
@@ -0,0 +1,49 @@
1
+ import { generateTypePresetStyles } from './generateTypePresetStyles';
2
+ import { presetMock } from './__mock__/presetMock';
3
+ import { layoutsMock } from './__mock__/layoutsMock';
4
+
5
+ describe('generateTypePresetStyles', () => {
6
+ it('generates blocks of styles', () => {
7
+ const styles = generateTypePresetStyles(presetMock, layoutsMock);
8
+ const expectedMedia = (id: string) =>
9
+ `@media (min-width: 0px) and (max-width: 767px) {
10
+ .cntrl-preset-${id} {
11
+ font-size: 5.3332999999999995vw;
12
+ line-height: 6.4vw;
13
+ letter-spacing: 0.8vw;
14
+ word-spacing: 0.8vw;
15
+ color: rgba(0, 0, 0, 1);
16
+ }
17
+ }
18
+ @media (min-width: 768px) and (max-width: 1023px) {
19
+ .cntrl-preset-${id} {
20
+ font-size: 2.604vw;
21
+ line-height: 3.125vw;
22
+ letter-spacing: 0vw;
23
+ word-spacing: 0vw;
24
+ color: rgba(0, 0, 0, 1);
25
+ }
26
+ }
27
+ @media (min-width: 1024px) {
28
+ .cntrl-preset-${id} {
29
+ font-size: 1.1111vw;
30
+ line-height: 1.3888vw;
31
+ letter-spacing: 0.06944vw;
32
+ word-spacing: 0.06944vw;
33
+ color: rgba(0, 0, 0, 1);
34
+ }
35
+ }`;
36
+ expect(styles).toBe(
37
+ `.cntrl-preset-heading01 {
38
+ font-family: Aeonik;
39
+ font-weight: 400;
40
+ }
41
+ ${expectedMedia('heading01')}
42
+ .cntrl-preset-heading02 {
43
+ font-family: Aeonik;
44
+ font-style: italic;
45
+ font-weight: 400;
46
+ }
47
+ ${expectedMedia('heading02')}`);
48
+ });
49
+ });
@@ -0,0 +1,25 @@
1
+ import { getLayoutMediaQuery, TLayout, TTypePresets } from '@cntrl-site/sdk';
2
+
3
+ const reEmptyLines = /^\s*\n/gm;
4
+
5
+ export function generateTypePresetStyles(preset: TTypePresets, layouts: TLayout[]): string {
6
+ const sorted = layouts.slice().sort((a, b) => a.startsWith - b.startsWith);
7
+ const stylesStr = (`
8
+ ${preset.presets.map(p => (`
9
+ .cntrl-preset-${p.id} {
10
+ font-family: ${p.fontFamily};
11
+ ${p.fontStyle.length > 0 ? `font-style: ${p.fontStyle};` : ''}
12
+ font-weight: ${p.fontWeight};
13
+ }
14
+ ${sorted.map(l => (`
15
+ ${getLayoutMediaQuery(l.id, sorted)} {
16
+ .cntrl-preset-${p.id} {
17
+ font-size: ${p.layoutParams[l.id].fontSize * 100}vw;
18
+ line-height: ${p.layoutParams[l.id].lineHeight * 100}vw;
19
+ letter-spacing: ${p.layoutParams[l.id].letterSpacing * 100}vw;
20
+ word-spacing: ${p.layoutParams[l.id].wordSpacing * 100}vw;
21
+ color: ${p.layoutParams[l.id].color};
22
+ }
23
+ }`)).join('\n')}`)).join('\n')}`);
24
+ return stylesStr.replace(reEmptyLines, '');
25
+ }
@@ -0,0 +1,43 @@
1
+ interface Range {
2
+ start: number;
3
+ end: number;
4
+ }
5
+
6
+ /**
7
+ * @param length
8
+ * @param ranges - SORTED array of ranges [start, end)
9
+ */
10
+
11
+ export function getInvertedRanges(length: number, ranges: Range[]): Range[] {
12
+ if (ranges.length === 0) {
13
+ return [{
14
+ start: 0,
15
+ end: length
16
+ }];
17
+ }
18
+ const inverted: Range[] = [];
19
+ if (ranges[0].start > 0) {
20
+ inverted.push({
21
+ start: 0,
22
+ end: ranges[0].start
23
+ });
24
+ }
25
+ for (let i = 0; i < ranges.length - 1; i += 1) {
26
+ const left = ranges[i];
27
+ const right = ranges[i + 1];
28
+ if (right.start - left.end > 0) {
29
+ inverted.push({
30
+ start: left.end,
31
+ end: right.start
32
+ });
33
+ }
34
+ }
35
+ const lastRange = ranges[ranges.length - 1];
36
+ if (lastRange.end < length) {
37
+ inverted.push({
38
+ start: lastRange.end,
39
+ end: length
40
+ });
41
+ }
42
+ return inverted;
43
+ }