@cntrl-site/sdk-nextjs 1.0.17 → 1.0.19-alpha.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 (38) hide show
  1. package/.idea/codeStyles/codeStyleConfig.xml +5 -0
  2. package/.idea/inspectionProfiles/Project_Default.xml +15 -0
  3. package/README.md +4 -1
  4. package/jest.config.js +2 -2
  5. package/lib/components/Article.js +9 -8
  6. package/lib/components/Item.js +32 -14
  7. package/lib/components/items/CodeEmbedItem.js +9 -8
  8. package/lib/components/items/CustomItem.js +8 -7
  9. package/lib/components/items/GroupItem.js +9 -8
  10. package/lib/components/items/ImageItem.js +13 -12
  11. package/lib/components/items/RectangleItem.js +9 -8
  12. package/lib/components/items/RichTextItem.js +8 -7
  13. package/lib/components/items/VideoItem.js +13 -12
  14. package/lib/components/items/VimeoEmbed.js +16 -15
  15. package/lib/components/items/YoutubeEmbed.js +14 -13
  16. package/lib/components/useStatesClassNames.js +18 -0
  17. package/lib/provider/InteractionsContext.js +45 -0
  18. package/lib/utils/{HoverStyles/HoverStyles.js → StateStyles/StateStyles.js} +18 -16
  19. package/lib/utils/getStatesCSS.js +16 -0
  20. package/package.json +7 -4
  21. package/src/components/Article.tsx +31 -28
  22. package/src/components/ArticleWrapper.tsx +1 -2
  23. package/src/components/Item.tsx +36 -19
  24. package/src/components/items/CodeEmbedItem.tsx +10 -9
  25. package/src/components/items/CustomItem.tsx +10 -9
  26. package/src/components/items/GroupItem.tsx +10 -9
  27. package/src/components/items/ImageItem.tsx +16 -15
  28. package/src/components/items/RectangleItem.tsx +11 -10
  29. package/src/components/items/RichTextItem.tsx +15 -9
  30. package/src/components/items/VideoItem.tsx +16 -15
  31. package/src/components/items/VimeoEmbed.tsx +17 -16
  32. package/src/components/items/YoutubeEmbed.tsx +15 -15
  33. package/src/components/useStatesClassNames.ts +23 -0
  34. package/src/provider/InteractionsContext.test.tsx +97 -0
  35. package/src/provider/InteractionsContext.tsx +65 -0
  36. package/src/utils/{HoverStyles/HoverStyles.ts → StateStyles/StateStyles.ts} +22 -21
  37. package/src/utils/getStatesCSS.ts +21 -0
  38. package/cntrl-site-sdk-nextjs-1.0.17.tgz +0 -0
@@ -0,0 +1,97 @@
1
+ import React from 'react';
2
+ import { render, waitFor } from '@testing-library/react';
3
+ import { InteractionsProvider, InteractionsContext } from './InteractionsContext';
4
+ import { Interaction } from '@cntrl-site/sdk';
5
+
6
+ describe('InteractionsProvider', () => {
7
+ const interactions: Interaction[] = [
8
+ {
9
+ id: 'interaction1',
10
+ startStateId: 'state1',
11
+ triggers: [
12
+ { itemId: 'item1', type: 'click', from: 'state1', to: 'state2' }
13
+ ],
14
+ states: [{ id: 'state1' }, { id: 'state2' }]
15
+ },
16
+ {
17
+ id: 'interaction2',
18
+ startStateId: 'state3',
19
+ triggers: [
20
+ { itemId: 'item2', type: 'hover-in', from: 'state3', to: 'state4' }
21
+ ],
22
+ states: [{ id: 'state3' }, { id: 'state4' }]
23
+ }
24
+ ];
25
+
26
+ it('should generate correct default interactionsStatesMap', () => {
27
+ let contextValue;
28
+
29
+ render(
30
+ <InteractionsProvider interactions={interactions}>
31
+ <InteractionsContext.Consumer>
32
+ {value => {
33
+ contextValue = value;
34
+ return null;
35
+ }}
36
+ </InteractionsContext.Consumer>
37
+ </InteractionsProvider>
38
+ );
39
+
40
+ expect(contextValue!).toBeDefined();
41
+ expect(contextValue!.interactionsStatesMap).toEqual({
42
+ interaction1: 'state1',
43
+ interaction2: 'state3'
44
+ });
45
+ });
46
+
47
+ it('should correctly update interactionsStatesMap when transitionTo is called', async () => {
48
+ let contextValue;
49
+
50
+ render(
51
+ <InteractionsProvider interactions={interactions}>
52
+ <InteractionsContext.Consumer>
53
+ {value => {
54
+ contextValue = value;
55
+ return null;
56
+ }}
57
+ </InteractionsContext.Consumer>
58
+ </InteractionsProvider>
59
+ );
60
+
61
+ expect(contextValue!).toBeDefined();
62
+ contextValue!.transitionTo('interaction1', 'state2');
63
+
64
+ await waitFor(() => {
65
+ expect(contextValue!.interactionsStatesMap['interaction1']).toBe('state2');
66
+ });
67
+ });
68
+
69
+ it('should return the correct trigger using getItemTrigger', () => {
70
+ let contextValue;
71
+
72
+ render(
73
+ <InteractionsProvider interactions={interactions}>
74
+ <InteractionsContext.Consumer>
75
+ {value => {
76
+ contextValue = value;
77
+ return null;
78
+ }}
79
+ </InteractionsContext.Consumer>
80
+ </InteractionsProvider>
81
+ );
82
+
83
+ expect(contextValue!).toBeDefined();
84
+
85
+ // Check the correct trigger is returned
86
+ const trigger = contextValue!.getItemTrigger('item1', 'click');
87
+ expect(trigger).toEqual({
88
+ id: 'interaction1',
89
+ from: 'state1',
90
+ to: 'state2',
91
+ });
92
+
93
+ // Check that no trigger is returned when conditions don't match
94
+ const noTrigger = contextValue!.getItemTrigger('item1', 'hover-on');
95
+ expect(noTrigger).toBeNull();
96
+ });
97
+ });
@@ -0,0 +1,65 @@
1
+ import { createContext, FC, PropsWithChildren, useState } from 'react';
2
+ import { Interaction, InteractionTrigger } from '@cntrl-site/sdk';
3
+
4
+ const defaultState = {
5
+ interactionsStatesMap: {},
6
+ interactions: [],
7
+ transitionTo: () => {},
8
+ getItemTrigger: () => null
9
+ };
10
+
11
+ export const InteractionsContext = createContext<{
12
+ interactionsStatesMap: StatesMap,
13
+ interactions: Interaction[],
14
+ transitionTo: (interactionId: string, stateId: string) => void,
15
+ getItemTrigger: (itemId: string, triggerType: TriggerType) => Trigger | null
16
+ }>(defaultState);
17
+
18
+ interface Props {
19
+ interactions: Interaction[];
20
+ }
21
+
22
+ export const InteractionsProvider: FC<PropsWithChildren<Props>> = ({ interactions, children }) => {
23
+ const defaultStatesMap = interactions.reduce<Record<string, string>>((map, { id, startStateId }) => {
24
+ map[id] = startStateId;
25
+ return map;
26
+ }, {});
27
+ const [interactionsStatesMap, setInteractionsStatesMap] = useState(defaultStatesMap);
28
+ const transitionTo = (interactionId: string, stateId: string) => {
29
+ setInteractionsStatesMap((map) => ({ ...map, [interactionId]: stateId }));
30
+ };
31
+ const getItemTrigger = (itemId: string, triggerType: TriggerType): Trigger | null => {
32
+ for (const interaction of interactions) {
33
+ const activeStateId = interactionsStatesMap[interaction.id];
34
+ const matchingTrigger = interaction.triggers.find((trigger) =>
35
+ trigger.itemId === itemId &&
36
+ trigger.from === activeStateId &&
37
+ trigger.type === triggerType
38
+ );
39
+ if (matchingTrigger) {
40
+ return {
41
+ id: interaction.id,
42
+ from: matchingTrigger.from,
43
+ to: matchingTrigger.to,
44
+ };
45
+ }
46
+ }
47
+ return null;
48
+ };
49
+ return (
50
+ <InteractionsContext.Provider value={{
51
+ transitionTo,
52
+ interactionsStatesMap,
53
+ interactions,
54
+ getItemTrigger
55
+ }}>
56
+ {children}
57
+ </InteractionsContext.Provider>
58
+ );
59
+ };
60
+
61
+ type StatesMap = Record<InteractionId, StateId>;
62
+ type Trigger = { id: InteractionId, from: StateId, to: StateId };
63
+ type TriggerType = InteractionTrigger['type'];
64
+ type InteractionId = string;
65
+ type StateId = string;
@@ -1,12 +1,11 @@
1
- import { HoverParams, ArticleItemType, AnchorSide, ItemHoverState } from '@cntrl-site/sdk';
1
+ import { StateParams, ArticleItemType, AnchorSide, ItemState } from '@cntrl-site/sdk';
2
2
  import { CntrlColor } from '@cntrl-site/color';
3
3
  import { getItemTopStyle } from '../getItemTopStyle';
4
4
 
5
5
  type UnionToIntersection<U> = (U extends any ? (arg: U) => void : never) extends (arg: infer I) => void ? I : never;
6
- type HoverParamsGetter = (value: any, anchorSide?: AnchorSide) => string;
7
- type ItemHoverParams = Omit<UnionToIntersection<ItemHoverState>, 'autoplay'>;
6
+ type StateParamsGetter = (value: any, anchorSide?: AnchorSide) => string;
8
7
 
9
- const hoverTransformationMap: Record<keyof ItemHoverParams, HoverParamsGetter> = {
8
+ const stateTransformationMap: Record<keyof ItemState<ArticleItemType>, StateParamsGetter> = {
10
9
  'width': (width: number) => `width: ${width * 100}vw !important;`,
11
10
  'height': (height: number) => `height: ${height * 100}vw !important;`,
12
11
  'top': (top: number, anchorSide?: AnchorSide) => `top: ${getItemTopStyle(top, anchorSide)} !important;`,
@@ -25,7 +24,7 @@ const hoverTransformationMap: Record<keyof ItemHoverParams, HoverParamsGetter> =
25
24
  'wordSpacing': (wordSpacing: number) => `word-spacing: ${wordSpacing * 100}vw !important;`
26
25
  };
27
26
 
28
- const CSSPropertyNameMap: Record<keyof ItemHoverParams, string> = {
27
+ const CSSPropertyNameMap: Record<keyof ItemState<ArticleItemType>, string> = {
29
28
  'width': 'width',
30
29
  'height': 'height',
31
30
  'top': 'top',
@@ -45,16 +44,17 @@ const CSSPropertyNameMap: Record<keyof ItemHoverParams, string> = {
45
44
  };
46
45
 
47
46
  export function getTransitions<T extends ArticleItemType>(
48
- values: Array<keyof ItemHoverParams>,
49
- hover?: ItemHoverParams
47
+ values: Array<keyof ItemState<ArticleItemType>>,
48
+ state?: ItemState<ArticleItemType>
50
49
  ): string {
51
- if (!hover) return 'unset';
50
+ if (!state) return 'unset';
52
51
  const transitionValues = values.reduce<string[]>((acc, valueName) => {
53
- if (valueName in hover && hover[valueName] !== undefined) {
54
- const hoverProperties = hover[valueName] as HoverParams<string | number>;
52
+ if (valueName in state && state[valueName] !== undefined) {
53
+ // @ts-ignore TODO
54
+ const stateProperties = state[valueName] as StateParams<string | number>;
55
55
  return [
56
56
  ...acc,
57
- `${CSSPropertyNameMap[valueName]} ${hoverProperties!.duration}ms ${hoverProperties!.timing} ${hoverProperties!.delay}ms`
57
+ `${CSSPropertyNameMap[valueName]} ${stateProperties!.duration}ms ${stateProperties!.timing} ${stateProperties!.delay}ms`
58
58
  ];
59
59
  }
60
60
  return acc;
@@ -63,23 +63,24 @@ export function getTransitions<T extends ArticleItemType>(
63
63
  return transitionValues.join(', ');
64
64
  }
65
65
 
66
- export function getHoverStyles<T extends ArticleItemType>(
67
- values: Array<keyof ItemHoverParams>,
68
- hover?: ItemHoverParams,
66
+ export function getStateStyles<T extends ArticleItemType>(
67
+ values: Array<keyof ItemState<ArticleItemType>>,
68
+ state?: ItemState<ArticleItemType>,
69
69
  anchorSide?: AnchorSide
70
70
  ): string {
71
- if (!hover) return '';
72
- const hoverValues = values.reduce<string[]>((acc, valueName) => {
73
- if (valueName in hover && hover[valueName] !== undefined) {
74
- const hoverProperties = hover[valueName] as HoverParams<string | number>;
71
+ if (!state) return '';
72
+ const stateValues = values.reduce<string[]>((acc, valueName) => {
73
+ if (valueName in state && state[valueName] !== undefined) {
74
+ // @ts-ignore TODO
75
+ const stateProperties = state[valueName] as StateParams<string | number>;
75
76
  return [
76
77
  ...acc,
77
- hoverTransformationMap[valueName](hoverProperties.value, anchorSide)
78
+ stateTransformationMap[valueName](stateProperties.value, anchorSide)
78
79
  ];
79
80
  }
80
81
  return acc;
81
82
  }, []);
82
- if (!hoverValues.length) return '';
83
- return hoverValues.join('\n');
83
+ if (!stateValues.length) return '';
84
+ return stateValues.join('\n');
84
85
  }
85
86
 
@@ -0,0 +1,21 @@
1
+ import { AnchorSide, ArticleItemType, ItemState } from '@cntrl-site/sdk';
2
+ import { getStateStyles } from './StateStyles/StateStyles';
3
+
4
+ export function getStatesCSS(
5
+ itemId: string,
6
+ classNamePrefix: string,
7
+ keys: Array<keyof ItemState<ArticleItemType>>,
8
+ states: Record<string, ItemState<ArticleItemType>> | undefined,
9
+ anchorSide?: AnchorSide
10
+ ) {
11
+ return states
12
+ ? Object.entries(states).map(([stateId, params]) => {
13
+ return `
14
+ .${classNamePrefix}-${itemId}-state-${stateId} {
15
+ ${getStateStyles(keys, params, anchorSide)};
16
+ }
17
+ `;
18
+ }).join('\n')
19
+ : '';
20
+ }
21
+
Binary file