@cntrl-site/sdk-nextjs 0.4.3 → 0.5.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.
Binary file
@@ -38,9 +38,6 @@ const useKeyframeValue = (item, itemParamsGetter, animatorGetter, deps = emptyDe
38
38
  }));
39
39
  return new Animator_1.Animator(animationData);
40
40
  }, [keyframes, layoutId]);
41
- (0, react_1.useEffect)(() => {
42
- setAdjustedValue(paramValue);
43
- }, [paramValue]);
44
41
  (0, react_1.useEffect)(() => {
45
42
  if (!animator || !articleRectObserver)
46
43
  return;
@@ -15,6 +15,8 @@ const useCntrlContext_1 = require("../provider/useCntrlContext");
15
15
  const useItemAngle_1 = require("./useItemAngle");
16
16
  const useItemPosition_1 = require("./useItemPosition");
17
17
  const useItemDimensions_1 = require("./useItemDimensions");
18
+ const useItemSticky_1 = require("./items/useItemSticky");
19
+ const castObject_1 = require("../utils/castObject");
18
20
  const itemsMap = {
19
21
  [sdk_1.ArticleItemType.Rectangle]: RectangleItem_1.RectangleItem,
20
22
  [sdk_1.ArticleItemType.Image]: ImageItem_1.ImageItem,
@@ -28,7 +30,10 @@ const noop = () => null;
28
30
  const Item = ({ item }) => {
29
31
  const { layouts } = (0, useCntrlContext_1.useCntrlContext)();
30
32
  const angle = (0, useItemAngle_1.useItemAngle)(item);
31
- const { top, left } = (0, useItemPosition_1.useItemPosition)(item);
33
+ const position = (0, useItemPosition_1.useItemPosition)(item);
34
+ const ref = (0, react_1.useRef)(null);
35
+ const [parentOffsetTop, setParentOffsetTop] = (0, react_1.useState)(0);
36
+ const { top, isFixed } = (0, useItemSticky_1.useItemSticky)(position.top, parentOffsetTop, item);
32
37
  const { width, height } = (0, useItemDimensions_1.useItemDimensions)(item);
33
38
  const layoutValues = [item.area];
34
39
  const isInitialRef = (0, react_1.useRef)(true);
@@ -40,19 +45,25 @@ const Item = ({ item }) => {
40
45
  (0, react_1.useEffect)(() => {
41
46
  isInitialRef.current = false;
42
47
  }, []);
48
+ (0, react_1.useEffect)(() => {
49
+ if (!ref.current)
50
+ return;
51
+ const offsetParent = (0, castObject_1.castObject)(ref.current.offsetParent, HTMLElement);
52
+ setParentOffsetTop(offsetParent.offsetTop / window.innerWidth);
53
+ }, []);
43
54
  const styles = {
44
55
  transform: `rotate(${angle}deg)`,
45
- left: `${left * 100}vw`,
56
+ left: `${position.left * 100}vw`,
46
57
  width: `${sizingAxis.x === sdk_1.ArticleItemSizingType.Manual ? `${width * 100}vw` : 'max-content'}`,
47
58
  height: `${sizingAxis.y === sdk_1.ArticleItemSizingType.Manual ? `${height * 100}vw` : 'unset'}`,
48
59
  top
49
60
  };
50
- return ((0, jsx_runtime_1.jsxs)("div", { suppressHydrationWarning: true, className: `item-${item.id}`, style: isInitialRef.current ? {} : styles, children: [(0, jsx_runtime_1.jsx)(ItemComponent, { item: item }), (0, jsx_runtime_1.jsx)("style", { jsx: true, children: `
61
+ return ((0, jsx_runtime_1.jsxs)("div", { suppressHydrationWarning: true, className: `item-${item.id}`, ref: ref, style: isInitialRef.current ? {} : { ...styles, position: isFixed ? 'fixed' : 'absolute' }, children: [(0, jsx_runtime_1.jsx)(ItemComponent, { item: item }), (0, jsx_runtime_1.jsx)("style", { jsx: true, children: `
51
62
  ${(0, sdk_1.getLayoutStyles)(layouts, layoutValues, ([area]) => (`
52
63
  .item-${item.id} {
53
64
  position: absolute;
54
65
  z-index: ${area.zIndex};
55
- top: ${(0, useItemPosition_1.getItemTopStyle)(area.top, area.anchorSide)};
66
+ top: ${(0, useItemSticky_1.getItemTopStyle)(area.top, area.anchorSide)};
56
67
  left: ${area.left * 100}vw;
57
68
  width: ${sizingAxis.x === sdk_1.ArticleItemSizingType.Manual ? `${area.width * 100}vw` : 'max-content'};
58
69
  height: ${sizingAxis.y === sdk_1.ArticleItemSizingType.Manual ? `${area.height * 100}vw` : 'unset'};
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getItemTopStyle = exports.useItemSticky = void 0;
4
+ const react_1 = require("react");
5
+ const sdk_1 = require("@cntrl-site/sdk");
6
+ const StickyManager_1 = require("../../utils/StickyManager/StickyManager");
7
+ const useCurrentLayout_1 = require("../../common/useCurrentLayout");
8
+ const ArticleRectContext_1 = require("../../provider/ArticleRectContext");
9
+ const useItemSticky = (top, parentOffsetTop, item) => {
10
+ const [isFixed, setIsFixed] = (0, react_1.useState)(false);
11
+ const [adjustedTop, setAdjustedTop] = (0, react_1.useState)(top);
12
+ const articleRectObserver = (0, react_1.useContext)(ArticleRectContext_1.ArticleRectContext);
13
+ const layoutId = (0, useCurrentLayout_1.useCurrentLayout)();
14
+ const sticky = (0, react_1.useMemo)(() => item.layoutParams[layoutId].sticky, [layoutId]);
15
+ const stickyManager = (0, react_1.useMemo)(() => new StickyManager_1.StickyManager(sticky), []);
16
+ const handleSticky = (0, react_1.useCallback)((scroll) => {
17
+ setIsFixed(stickyManager.getIsSticky(scroll));
18
+ setAdjustedTop(stickyManager.getPosition(scroll, top, parentOffsetTop));
19
+ }, [top, stickyManager]);
20
+ (0, react_1.useEffect)(() => {
21
+ if (!articleRectObserver || !sticky)
22
+ return;
23
+ return articleRectObserver.on('scroll', () => {
24
+ handleSticky(articleRectObserver.scroll);
25
+ });
26
+ }, [handleSticky, articleRectObserver, sticky]);
27
+ return {
28
+ isFixed,
29
+ top: sticky ? `${adjustedTop * 100}vw` : getItemTopStyle(adjustedTop, layoutId ? item.area[layoutId].anchorSide : sdk_1.AnchorSide.Top)
30
+ };
31
+ };
32
+ exports.useItemSticky = useItemSticky;
33
+ function getItemTopStyle(top, anchorSide) {
34
+ const defaultValue = `${top * 100}vw`;
35
+ if (!anchorSide)
36
+ return defaultValue;
37
+ switch (anchorSide) {
38
+ case sdk_1.AnchorSide.Top:
39
+ return defaultValue;
40
+ case sdk_1.AnchorSide.Center:
41
+ return `calc(50% + ${top * 100}vw)`;
42
+ case sdk_1.AnchorSide.Bottom:
43
+ return `calc(100% + ${top * 100}vw)`;
44
+ }
45
+ }
46
+ exports.getItemTopStyle = getItemTopStyle;
@@ -1,34 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getItemTopStyle = exports.useItemPosition = void 0;
4
- const sdk_1 = require("@cntrl-site/sdk");
3
+ exports.useItemPosition = void 0;
5
4
  const useKeyframeValue_1 = require("../common/useKeyframeValue");
6
5
  const useCurrentLayout_1 = require("../common/useCurrentLayout");
7
- const defaultArea = {
8
- left: 0,
9
- top: 0,
10
- width: 0,
11
- height: 0,
12
- angle: 0,
13
- zIndex: 0
14
- };
15
6
  const useItemPosition = (item) => {
16
7
  const layoutId = (0, useCurrentLayout_1.useCurrentLayout)();
17
8
  const { top, left } = (0, useKeyframeValue_1.useKeyframeValue)(item, (item, layoutId) => item.area[layoutId], (animator, scroll, value) => animator.getPositions(value, scroll), [layoutId]);
18
- return { top: getItemTopStyle(top, layoutId ? item.area[layoutId].anchorSide : sdk_1.AnchorSide.Top), left };
9
+ return { top, left };
19
10
  };
20
11
  exports.useItemPosition = useItemPosition;
21
- function getItemTopStyle(top, anchorSide) {
22
- const defaultValue = `${top * 100}vw`;
23
- if (!anchorSide)
24
- return defaultValue;
25
- switch (anchorSide) {
26
- case sdk_1.AnchorSide.Top:
27
- return defaultValue;
28
- case sdk_1.AnchorSide.Center:
29
- return `calc(50% + ${top * 100}vw)`;
30
- case sdk_1.AnchorSide.Bottom:
31
- return `calc(100% + ${top * 100}vw)`;
32
- }
33
- }
34
- exports.getItemTopStyle = getItemTopStyle;
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.StickyManager = void 0;
4
+ class StickyManager {
5
+ constructor(sticky) {
6
+ this.sticky = sticky;
7
+ }
8
+ getIsSticky(scroll) {
9
+ if (!this.sticky)
10
+ return false;
11
+ return (this.sticky.from <= scroll) && (!this.sticky.to || this.sticky.to >= scroll);
12
+ }
13
+ getPosition(scroll, top, offsetTop) {
14
+ if (!this.sticky)
15
+ return top;
16
+ if (this.getIsSticky(scroll)) {
17
+ return top - this.sticky.from + offsetTop;
18
+ }
19
+ if (this.sticky.to !== undefined && this.sticky.to <= scroll) {
20
+ return top + this.sticky.to - this.sticky.from;
21
+ }
22
+ return top;
23
+ }
24
+ }
25
+ exports.StickyManager = StickyManager;
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.castObject = void 0;
4
+ function castObject(value, ctor) {
5
+ if (value instanceof ctor) {
6
+ return value;
7
+ }
8
+ throw new TypeError(`passed value "${String(value)}" is not instance of ${ctor.name}`);
9
+ }
10
+ exports.castObject = castObject;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cntrl-site/sdk-nextjs",
3
- "version": "0.4.3",
3
+ "version": "0.5.0",
4
4
  "description": "SDK for Next.js",
5
5
  "main": "lib/index.js",
6
6
  "types": "src/index.js",
@@ -21,7 +21,7 @@
21
21
  },
22
22
  "homepage": "https://github.com/cntrl-site/sdk-nextjs#readme",
23
23
  "dependencies": {
24
- "@cntrl-site/sdk": "^0.4.2",
24
+ "@cntrl-site/sdk": "^0.4.3",
25
25
  "html-react-parser": "^3.0.1",
26
26
  "styled-jsx": "^5.0.2"
27
27
  },
@@ -46,10 +46,6 @@ export const useKeyframeValue = <T>(
46
46
  return new Animator(animationData);
47
47
  }, [keyframes, layoutId]);
48
48
 
49
- useEffect(() => {
50
- setAdjustedValue(paramValue);
51
- }, [paramValue]);
52
-
53
49
  useEffect(() => {
54
50
  if (!animator || !articleRectObserver) return;
55
51
  return articleRectObserver.on('resize', () => {
@@ -1,4 +1,4 @@
1
- import { ComponentType, FC, useEffect, useRef } from 'react';
1
+ import { ComponentType, FC, useEffect, useRef, useState } from 'react';
2
2
  import {
3
3
  getLayoutStyles,
4
4
  ArticleItemType,
@@ -14,8 +14,10 @@ import { YoutubeEmbedItem } from './items/YoutubeEmbed';
14
14
  import { CustomItem } from './items/CustomItem';
15
15
  import { useCntrlContext } from '../provider/useCntrlContext';
16
16
  import { useItemAngle } from './useItemAngle';
17
- import { getItemTopStyle, useItemPosition } from './useItemPosition';
17
+ import { useItemPosition } from './useItemPosition';
18
18
  import { useItemDimensions } from './useItemDimensions';
19
+ import { getItemTopStyle, useItemSticky } from './items/useItemSticky';
20
+ import { castObject } from '../utils/castObject';
19
21
 
20
22
  export interface ItemProps<I extends TArticleItemAny> {
21
23
  item: I;
@@ -36,7 +38,10 @@ const noop = () => null;
36
38
  export const Item: FC<ItemProps<TArticleItemAny>> = ({ item }) => {
37
39
  const { layouts } = useCntrlContext();
38
40
  const angle = useItemAngle(item);
39
- const { top, left } = useItemPosition(item);
41
+ const position = useItemPosition(item);
42
+ const ref = useRef<HTMLDivElement | null>(null);
43
+ const [parentOffsetTop, setParentOffsetTop] = useState(0);
44
+ const { top, isFixed } = useItemSticky(position.top, parentOffsetTop, item);
40
45
  const { width, height } = useItemDimensions(item);
41
46
  const layoutValues: Record<string, any>[] = [item.area];
42
47
  const isInitialRef = useRef(true);
@@ -51,9 +56,15 @@ export const Item: FC<ItemProps<TArticleItemAny>> = ({ item }) => {
51
56
  isInitialRef.current = false;
52
57
  }, []);
53
58
 
59
+ useEffect(() => {
60
+ if (!ref.current) return;
61
+ const offsetParent = castObject(ref.current.offsetParent, HTMLElement);
62
+ setParentOffsetTop(offsetParent.offsetTop / window.innerWidth);
63
+ }, []);
64
+
54
65
  const styles = {
55
66
  transform: `rotate(${angle}deg)`,
56
- left: `${left * 100}vw`,
67
+ left: `${position.left * 100}vw`,
57
68
  width: `${sizingAxis.x === SizingType.Manual ? `${width * 100}vw` : 'max-content'}`,
58
69
  height: `${sizingAxis.y === SizingType.Manual ? `${height * 100}vw` : 'unset'}`,
59
70
  top
@@ -63,7 +74,8 @@ export const Item: FC<ItemProps<TArticleItemAny>> = ({ item }) => {
63
74
  <div
64
75
  suppressHydrationWarning={true}
65
76
  className={`item-${item.id}`}
66
- style={isInitialRef.current ? {} : styles }
77
+ ref={ref}
78
+ style={isInitialRef.current ? {} : { ...styles, position: isFixed ? 'fixed': 'absolute' } }
67
79
  >
68
80
  <ItemComponent item={item} />
69
81
  <style jsx>{`
@@ -0,0 +1,47 @@
1
+ import { useCallback, useContext, useEffect, useMemo, useState } from 'react';
2
+ import { AnchorSide, TArticleItemAny } from '@cntrl-site/sdk';
3
+ import { StickyManager } from '../../utils/StickyManager/StickyManager';
4
+ import { useCurrentLayout } from '../../common/useCurrentLayout';
5
+ import { ArticleRectContext } from '../../provider/ArticleRectContext';
6
+
7
+ export const useItemSticky = (top: number, parentOffsetTop: number, item: TArticleItemAny) => {
8
+ const [isFixed, setIsFixed] = useState(false);
9
+ const [adjustedTop, setAdjustedTop] = useState(top);
10
+ const articleRectObserver = useContext(ArticleRectContext);
11
+ const layoutId = useCurrentLayout();
12
+ const sticky = useMemo(() => item.layoutParams[layoutId].sticky, [layoutId]);
13
+ const stickyManager = useMemo(() => new StickyManager(sticky), []);
14
+
15
+ const handleSticky = useCallback((scroll: number) => {
16
+ setIsFixed(stickyManager.getIsSticky(scroll));
17
+ setAdjustedTop(stickyManager.getPosition(
18
+ scroll,
19
+ top,
20
+ parentOffsetTop
21
+ ));
22
+ }, [top, stickyManager]);
23
+
24
+ useEffect(() => {
25
+ if (!articleRectObserver || !sticky) return;
26
+ return articleRectObserver.on('scroll', () => {
27
+ handleSticky(articleRectObserver.scroll);
28
+ });
29
+ }, [handleSticky, articleRectObserver, sticky]);
30
+ return {
31
+ isFixed,
32
+ top: sticky ? `${adjustedTop * 100}vw` : getItemTopStyle(adjustedTop, layoutId ? item.area[layoutId].anchorSide : AnchorSide.Top)
33
+ };
34
+ };
35
+
36
+ export function getItemTopStyle(top: number, anchorSide?: AnchorSide) {
37
+ const defaultValue = `${top * 100}vw`;
38
+ if (!anchorSide) return defaultValue;
39
+ switch (anchorSide) {
40
+ case AnchorSide.Top:
41
+ return defaultValue;
42
+ case AnchorSide.Center:
43
+ return `calc(50% + ${top * 100}vw)`;
44
+ case AnchorSide.Bottom:
45
+ return `calc(100% + ${top * 100}vw)`;
46
+ }
47
+ }
@@ -1,36 +1,15 @@
1
- import { AnchorSide, TArticleItemAny } from '@cntrl-site/sdk';
1
+ import { TArticleItemAny } from '@cntrl-site/sdk';
2
2
  import { useKeyframeValue } from '../common/useKeyframeValue';
3
3
  import { useCurrentLayout } from '../common/useCurrentLayout';
4
4
 
5
- const defaultArea = {
6
- left: 0,
7
- top: 0,
8
- width: 0,
9
- height: 0,
10
- angle: 0,
11
- zIndex: 0
12
- };
13
-
14
5
  export const useItemPosition = (item: TArticleItemAny) => {
15
- const layoutId = useCurrentLayout()
6
+ const layoutId = useCurrentLayout();
16
7
  const { top, left } = useKeyframeValue<{ top: number; left: number }>(
17
8
  item,
18
9
  (item, layoutId) => item.area[layoutId],
19
10
  (animator, scroll, value) => animator.getPositions(value, scroll),
20
11
  [layoutId]
21
12
  );
22
- return { top: getItemTopStyle(top, layoutId ? item.area[layoutId].anchorSide : AnchorSide.Top), left };
13
+ return { top, left };
23
14
  };
24
15
 
25
- export function getItemTopStyle(top: number, anchorSide?: AnchorSide) {
26
- const defaultValue = `${top * 100}vw`;
27
- if (!anchorSide) return defaultValue;
28
- switch (anchorSide) {
29
- case AnchorSide.Top:
30
- return defaultValue;
31
- case AnchorSide.Center:
32
- return `calc(50% + ${top * 100}vw)`;
33
- case AnchorSide.Bottom:
34
- return `calc(100% + ${top * 100}vw)`;
35
- }
36
- }
@@ -0,0 +1,23 @@
1
+ export type TSticky = { from: number; to?: number; } | null;
2
+
3
+ export class StickyManager {
4
+ constructor(
5
+ private sticky: TSticky
6
+ ) {}
7
+
8
+ getIsSticky(scroll: number): boolean {
9
+ if (!this.sticky) return false;
10
+ return (this.sticky.from <= scroll) && (!this.sticky.to || this.sticky.to >= scroll);
11
+ }
12
+
13
+ getPosition(scroll: number, top: number, offsetTop: number): number {
14
+ if (!this.sticky) return top;
15
+ if (this.getIsSticky(scroll)) {
16
+ return top - this.sticky.from + offsetTop;
17
+ }
18
+ if (this.sticky.to !== undefined && this.sticky.to <= scroll) {
19
+ return top + this.sticky.to - this.sticky.from;
20
+ }
21
+ return top;
22
+ }
23
+ }
@@ -0,0 +1,10 @@
1
+ type Ctor = {
2
+ new(...args: any): any;
3
+ };
4
+
5
+ export function castObject<O extends Ctor>(value: unknown, ctor: O): InstanceType<O> {
6
+ if (value instanceof ctor) {
7
+ return value;
8
+ }
9
+ throw new TypeError(`passed value "${String(value)}" is not instance of ${ctor.name}`);
10
+ }
@@ -1,15 +0,0 @@
1
- <component name="InspectionProjectProfileManager">
2
- <profile version="1.0">
3
- <option name="myName" value="Project Default" />
4
- <inspection_tool class="HtmlUnknownAttribute" enabled="true" level="WARNING" enabled_by_default="true">
5
- <option name="myValues">
6
- <value>
7
- <list size="1">
8
- <item index="0" class="java.lang.String" itemvalue="jsx" />
9
- </list>
10
- </value>
11
- </option>
12
- <option name="myCustomValuesEnabled" value="true" />
13
- </inspection_tool>
14
- </profile>
15
- </component>
Binary file