@cntrl-site/sdk-nextjs 0.5.0 → 0.6.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.
@@ -6,7 +6,6 @@ const react_1 = require("react");
6
6
  const ArticleRectContext_1 = require("../provider/ArticleRectContext");
7
7
  const useCurrentLayout = () => {
8
8
  const { layouts } = (0, useCntrlContext_1.useCntrlContext)();
9
- const [initialLayout] = layouts;
10
9
  const articleRectObserver = (0, react_1.useContext)(ArticleRectContext_1.ArticleRectContext);
11
10
  const layoutRanges = (0, react_1.useMemo)(() => {
12
11
  const sorted = layouts.slice().sort((la, lb) => la.startsWith - lb.startsWith);
@@ -25,7 +24,7 @@ const useCurrentLayout = () => {
25
24
  const getCurrentLayout = (0, react_1.useCallback)((articleWidth) => {
26
25
  return layoutRanges.find(l => articleWidth >= l.start && articleWidth < l.end).layoutId;
27
26
  }, [layoutRanges]);
28
- const [layoutId, setLayoutId] = (0, react_1.useState)(getCurrentLayout(isServer() ? 0 : window.innerWidth));
27
+ const [layoutId, setLayoutId] = (0, react_1.useState)(getCurrentLayout(0));
29
28
  (0, react_1.useEffect)(() => {
30
29
  if (!articleRectObserver)
31
30
  return;
@@ -37,6 +36,3 @@ const useCurrentLayout = () => {
37
36
  return layoutId;
38
37
  };
39
38
  exports.useCurrentLayout = useCurrentLayout;
40
- function isServer() {
41
- return typeof window === 'undefined';
42
- }
@@ -38,6 +38,9 @@ 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]);
41
44
  (0, react_1.useEffect)(() => {
42
45
  if (!animator || !articleRectObserver)
43
46
  return;
@@ -31,7 +31,7 @@ const Item = ({ item }) => {
31
31
  const { layouts } = (0, useCntrlContext_1.useCntrlContext)();
32
32
  const angle = (0, useItemAngle_1.useItemAngle)(item);
33
33
  const position = (0, useItemPosition_1.useItemPosition)(item);
34
- const ref = (0, react_1.useRef)(null);
34
+ const [ref, setRef] = (0, react_1.useState)(null);
35
35
  const [parentOffsetTop, setParentOffsetTop] = (0, react_1.useState)(0);
36
36
  const { top, isFixed } = (0, useItemSticky_1.useItemSticky)(position.top, parentOffsetTop, item);
37
37
  const { width, height } = (0, useItemDimensions_1.useItemDimensions)(item);
@@ -46,11 +46,11 @@ const Item = ({ item }) => {
46
46
  isInitialRef.current = false;
47
47
  }, []);
48
48
  (0, react_1.useEffect)(() => {
49
- if (!ref.current)
49
+ if (!ref)
50
50
  return;
51
- const offsetParent = (0, castObject_1.castObject)(ref.current.offsetParent, HTMLElement);
51
+ const offsetParent = (0, castObject_1.castObject)(ref.offsetParent, HTMLElement);
52
52
  setParentOffsetTop(offsetParent.offsetTop / window.innerWidth);
53
- }, []);
53
+ }, [ref]);
54
54
  const styles = {
55
55
  transform: `rotate(${angle}deg)`,
56
56
  left: `${position.left * 100}vw`,
@@ -58,7 +58,7 @@ const Item = ({ item }) => {
58
58
  height: `${sizingAxis.y === sdk_1.ArticleItemSizingType.Manual ? `${height * 100}vw` : 'unset'}`,
59
59
  top
60
60
  };
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: `
61
+ return ((0, jsx_runtime_1.jsxs)("div", { suppressHydrationWarning: true, className: `item-${item.id}`, ref: setRef, 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: `
62
62
  ${(0, sdk_1.getLayoutStyles)(layouts, layoutValues, ([area]) => (`
63
63
  .item-${item.id} {
64
64
  position: absolute;
@@ -4,8 +4,10 @@ exports.Section = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
5
  const sdk_1 = require("@cntrl-site/sdk");
6
6
  const useCntrlContext_1 = require("../provider/useCntrlContext");
7
+ const useSectionColor_1 = require("./useSectionColor");
7
8
  const Section = ({ section, children }) => {
8
9
  const { layouts } = (0, useCntrlContext_1.useCntrlContext)();
10
+ const backgroundColor = (0, useSectionColor_1.useSectionColor)(section.color);
9
11
  const getSectionVisibilityStyles = () => {
10
12
  return layouts
11
13
  .sort((a, b) => a.startsWith - b.startsWith)
@@ -20,16 +22,14 @@ const Section = ({ section, children }) => {
20
22
  }`;
21
23
  }, '');
22
24
  };
23
- return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { className: `section-${section.id}`, children: children }), (0, jsx_runtime_1.jsx)("style", { jsx: true, children: `
25
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { className: `section-${section.id}`, style: {
26
+ backgroundColor: backgroundColor
27
+ }, children: children }), (0, jsx_runtime_1.jsx)("style", { jsx: true, children: `
24
28
  ${(0, sdk_1.getLayoutStyles)(layouts, [section.height], ([height]) => (`
25
29
  .section-${section.id} {
26
30
  height: ${getSectionHeight(height)};
27
31
  position: relative;
28
32
  }`))}
29
- ${(0, sdk_1.getLayoutStyles)(layouts, [section.color], ([color]) => (`
30
- .section-${section.id} {
31
- background-color: ${color ? color : 'transparent'};
32
- }`))}
33
33
  ${getSectionVisibilityStyles()}
34
34
  ` })] }));
35
35
  };
@@ -2,15 +2,18 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ImageItem = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const react_1 = require("react");
6
+ const sdk_1 = require("@cntrl-site/sdk");
5
7
  const LinkWrapper_1 = require("../LinkWrapper");
6
8
  const useFileItem_1 = require("./useFileItem");
7
9
  const ImageItem = ({ item }) => {
8
10
  const { radius, strokeWidth, opacity, strokeColor } = (0, useFileItem_1.useFileItem)(item);
11
+ const borderColor = (0, react_1.useMemo)(() => sdk_1.CntrlColor.parse(strokeColor).toCss(), [strokeColor]);
9
12
  return ((0, jsx_runtime_1.jsx)(LinkWrapper_1.LinkWrapper, { url: item.link?.url, children: (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { className: `image-wrapper-${item.id}`, style: {
10
13
  borderRadius: `${radius * 100}vw`,
11
14
  borderWidth: `${strokeWidth * 100}vw`,
12
15
  opacity: `${opacity}`,
13
- borderColor: `${strokeColor}`
16
+ borderColor: `${borderColor}`
14
17
  }, children: (0, jsx_runtime_1.jsx)("img", { className: "image", src: item.commonParams.url }) }), (0, jsx_runtime_1.jsx)("style", { jsx: true, children: `
15
18
  .image-wrapper-${item.id} {
16
19
  position: absolute;
@@ -2,15 +2,19 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.RectangleItem = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const react_1 = require("react");
6
+ const sdk_1 = require("@cntrl-site/sdk");
5
7
  const LinkWrapper_1 = require("../LinkWrapper");
6
8
  const useRectangleItem_1 = require("./useRectangleItem");
7
9
  const RectangleItem = ({ item }) => {
8
10
  const { fillColor, radius, strokeWidth, strokeColor } = (0, useRectangleItem_1.useRectangleItem)(item);
11
+ const backgroundColor = (0, react_1.useMemo)(() => sdk_1.CntrlColor.parse(fillColor).toCss(), [fillColor]);
12
+ const borderColor = (0, react_1.useMemo)(() => sdk_1.CntrlColor.parse(strokeColor).toCss(), [strokeColor]);
9
13
  return ((0, jsx_runtime_1.jsx)(LinkWrapper_1.LinkWrapper, { url: item.link?.url, children: (0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { className: `rectangle-${item.id}`, style: {
10
- backgroundColor: `${fillColor}`,
14
+ backgroundColor: `${backgroundColor}`,
11
15
  borderRadius: `${radius * 100}vw`,
12
16
  borderWidth: `${strokeWidth * 100}vw`,
13
- borderColor: `${strokeColor}`
17
+ borderColor: `${borderColor}`
14
18
  } }), (0, jsx_runtime_1.jsx)("style", { jsx: true, children: `
15
19
  .rectangle-${item.id} {
16
20
  position: absolute;
@@ -2,15 +2,18 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.VideoItem = void 0;
4
4
  const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const react_1 = require("react");
6
+ const sdk_1 = require("@cntrl-site/sdk");
5
7
  const LinkWrapper_1 = require("../LinkWrapper");
6
8
  const useFileItem_1 = require("./useFileItem");
7
9
  const VideoItem = ({ item }) => {
8
10
  const { radius, strokeWidth, strokeColor, opacity } = (0, useFileItem_1.useFileItem)(item);
11
+ const borderColor = (0, react_1.useMemo)(() => sdk_1.CntrlColor.parse(strokeColor).toCss(), [strokeColor]);
9
12
  return ((0, jsx_runtime_1.jsxs)(LinkWrapper_1.LinkWrapper, { url: item.link?.url, children: [(0, jsx_runtime_1.jsx)("div", { className: `video-wrapper-${item.id}`, style: {
10
13
  borderRadius: `${radius * 100}vw`,
11
14
  borderWidth: `${strokeWidth * 100}vw`,
12
15
  opacity: `${opacity}`,
13
- borderColor: `${strokeColor}`
16
+ borderColor: `${borderColor}`
14
17
  }, children: (0, jsx_runtime_1.jsx)("video", { autoPlay: true, muted: true, loop: true, playsInline: true, className: "video", children: (0, jsx_runtime_1.jsx)("source", { src: item.commonParams.url }) }) }), (0, jsx_runtime_1.jsx)("style", { jsx: true, children: `
15
18
  .video-wrapper-${item.id} {
16
19
  position: absolute;
@@ -16,7 +16,7 @@ const useItemSticky = (top, parentOffsetTop, item) => {
16
16
  const handleSticky = (0, react_1.useCallback)((scroll) => {
17
17
  setIsFixed(stickyManager.getIsSticky(scroll));
18
18
  setAdjustedTop(stickyManager.getPosition(scroll, top, parentOffsetTop));
19
- }, [top, stickyManager]);
19
+ }, [top, stickyManager, parentOffsetTop]);
20
20
  (0, react_1.useEffect)(() => {
21
21
  if (!articleRectObserver || !sticky)
22
22
  return;
@@ -23,13 +23,13 @@ const useRectangleItem = (item) => {
23
23
  return defaultColor;
24
24
  const layoutParams = item.layoutParams[layoutId];
25
25
  return 'fillColor' in layoutParams ? layoutParams.fillColor : defaultColor;
26
- }, (animator, scroll, value) => animator.getColor({ color: value }, scroll).color);
26
+ }, (animator, scroll, value) => animator.getColor({ color: value }, scroll).color, [layoutId]);
27
27
  const strokeColor = (0, useKeyframeValue_1.useKeyframeValue)(item, (item, layoutId) => {
28
28
  if (!layoutId)
29
29
  return defaultColor;
30
30
  const layoutParams = item.layoutParams[layoutId];
31
31
  return 'strokeColor' in layoutParams ? layoutParams.strokeColor : defaultColor;
32
- }, (animator, scroll, value) => animator.getBorderColor({ color: value }, scroll).color);
32
+ }, (animator, scroll, value) => animator.getBorderColor({ color: value }, scroll).color, [layoutId]);
33
33
  return { fillColor, strokeWidth, radius, strokeColor };
34
34
  };
35
35
  exports.useRectangleItem = useRectangleItem;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useSectionColor = void 0;
4
+ const useCurrentLayout_1 = require("../common/useCurrentLayout");
5
+ const react_1 = require("react");
6
+ const sdk_1 = require("@cntrl-site/sdk");
7
+ const DEFAULT_COLOR = 'transparent';
8
+ const useSectionColor = (colorData) => {
9
+ const layoutId = (0, useCurrentLayout_1.useCurrentLayout)();
10
+ return (0, react_1.useMemo)(() => {
11
+ const layoutColor = colorData[layoutId];
12
+ return !layoutColor ? DEFAULT_COLOR : sdk_1.CntrlColor.parse(layoutColor).toCss();
13
+ }, []);
14
+ };
15
+ exports.useSectionColor = useSectionColor;
@@ -60,7 +60,7 @@ class Animator {
60
60
  }
61
61
  const { start, end } = this.getStartEnd(pos, keyframes);
62
62
  return {
63
- color: this.getRgba(start, end, pos)
63
+ color: this.getRangeColor(start, end, pos)
64
64
  };
65
65
  }
66
66
  getBorderColor(values, pos) {
@@ -75,7 +75,7 @@ class Animator {
75
75
  }
76
76
  const { start, end } = this.getStartEnd(pos, keyframes);
77
77
  return {
78
- color: this.getRgba(start, end, pos)
78
+ color: this.getRangeColor(start, end, pos)
79
79
  };
80
80
  }
81
81
  getRadius(values, pos) {
@@ -150,25 +150,15 @@ class Animator {
150
150
  Animator.pushKeyframeToMap(keyframe, this.keyframesMap);
151
151
  }
152
152
  }
153
- getRgba(start, end, position) {
154
- const [startR, startG, startB, startA] = parseRgba(start.value.color);
155
- const [endR, endG, endB, endA] = parseRgba(end.value.color);
156
- const r = rangeMap(position, start.position, end.position, startR, endR, true);
157
- const g = rangeMap(position, start.position, end.position, startG, endG, true);
158
- const b = rangeMap(position, start.position, end.position, startB, endB, true);
159
- const a = rangeMap(position, start.position, end.position, startA, endA, true);
160
- return `rgba(${r},${g},${b},${a})`;
153
+ getRangeColor(start, end, position) {
154
+ const rangeAmount = rangeMap(position, start.position, end.position, 0, 1, true);
155
+ const startColor = sdk_1.CntrlColor.parse(start.value.color);
156
+ const endColor = sdk_1.CntrlColor.parse(end.value.color);
157
+ const mixedColor = startColor.mix(endColor, rangeAmount);
158
+ return mixedColor.fmt('oklch');
161
159
  }
162
160
  }
163
161
  exports.Animator = Animator;
164
- const reRgba = /^rgba?\( *(\d+) *, *(\d+) *, *(\d+)(?: *, *(\d+(?:\.\d+)?))? *\)$/i;
165
- function parseRgba(color) {
166
- const match = reRgba.exec(color);
167
- if (!match)
168
- return [0, 0, 0, 1];
169
- const [, r, g, b, a] = match;
170
- return [parseInt(r, 10), parseInt(g, 10), parseInt(b, 10), a ? parseFloat(a) : NaN];
171
- }
172
162
  function createKeyframesMap() {
173
163
  return {
174
164
  [sdk_1.KeyframeType.Dimensions]: [],
@@ -187,7 +187,7 @@ class RichTextConverter {
187
187
  static fromDraftToInline(draftStyle) {
188
188
  const { value, name } = draftStyle;
189
189
  const map = {
190
- 'COLOR': { 'color': value },
190
+ 'COLOR': { 'color': getResolvedValue(value, name) },
191
191
  'TYPEFACE': { 'font-family': `${value}` },
192
192
  'FONTSTYLE': value ? { ...exports.FontStyles[value] } : {},
193
193
  'FONTWEIGHT': { 'font-weight': value },
@@ -218,3 +218,8 @@ function groupBy(items, getKey) {
218
218
  }
219
219
  return groups;
220
220
  }
221
+ function getResolvedValue(value, name) {
222
+ if (name !== 'COLOR')
223
+ return value;
224
+ return value ? sdk_1.CntrlColor.parse(value).toCss() : value;
225
+ }
@@ -19,7 +19,7 @@ ${(0, sdk_1.getLayoutMediaQuery)(l.id, sorted)} {
19
19
  line-height: ${p.layoutParams[l.id].lineHeight * 100}vw;
20
20
  letter-spacing: ${p.layoutParams[l.id].letterSpacing * 100}vw;
21
21
  word-spacing: ${p.layoutParams[l.id].wordSpacing * 100}vw;
22
- color: ${p.layoutParams[l.id].color};
22
+ color: ${sdk_1.CntrlColor.parse(p.layoutParams[l.id].color).toCss()};
23
23
  }
24
24
  }`)).join('\n')}`)).join('\n')}`);
25
25
  return stylesStr.replace(reEmptyLines, '');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cntrl-site/sdk-nextjs",
3
- "version": "0.5.0",
3
+ "version": "0.6.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.3",
24
+ "@cntrl-site/sdk": "^0.4.4",
25
25
  "html-react-parser": "^3.0.1",
26
26
  "styled-jsx": "^5.0.2"
27
27
  },
@@ -10,7 +10,6 @@ interface LayoutData {
10
10
 
11
11
  export const useCurrentLayout = () => {
12
12
  const { layouts } = useCntrlContext();
13
- const [initialLayout] = layouts;
14
13
  const articleRectObserver = useContext(ArticleRectContext);
15
14
  const layoutRanges = useMemo(() => {
16
15
  const sorted = layouts.slice().sort((la, lb) => la.startsWith - lb.startsWith);
@@ -29,7 +28,7 @@ export const useCurrentLayout = () => {
29
28
  const getCurrentLayout = useCallback((articleWidth: number) => {
30
29
  return layoutRanges.find(l => articleWidth >= l.start && articleWidth < l.end)!.layoutId;
31
30
  }, [layoutRanges]);
32
- const [layoutId, setLayoutId] = useState<string>(getCurrentLayout(isServer() ? 0 : window.innerWidth));
31
+ const [layoutId, setLayoutId] = useState<string>(getCurrentLayout(0));
33
32
 
34
33
  useEffect(() => {
35
34
  if (!articleRectObserver) return;
@@ -41,7 +40,3 @@ export const useCurrentLayout = () => {
41
40
 
42
41
  return layoutId;
43
42
  };
44
-
45
- function isServer(): boolean {
46
- return typeof window === 'undefined';
47
- }
@@ -46,6 +46,10 @@ export const useKeyframeValue = <T>(
46
46
  return new Animator(animationData);
47
47
  }, [keyframes, layoutId]);
48
48
 
49
+ useEffect(() => {
50
+ setAdjustedValue(paramValue);
51
+ }, [paramValue]);
52
+
49
53
  useEffect(() => {
50
54
  if (!animator || !articleRectObserver) return;
51
55
  return articleRectObserver.on('resize', () => {
@@ -39,7 +39,7 @@ export const Item: FC<ItemProps<TArticleItemAny>> = ({ item }) => {
39
39
  const { layouts } = useCntrlContext();
40
40
  const angle = useItemAngle(item);
41
41
  const position = useItemPosition(item);
42
- const ref = useRef<HTMLDivElement | null>(null);
42
+ const [ref, setRef] = useState<HTMLDivElement | null>(null);
43
43
  const [parentOffsetTop, setParentOffsetTop] = useState(0);
44
44
  const { top, isFixed } = useItemSticky(position.top, parentOffsetTop, item);
45
45
  const { width, height } = useItemDimensions(item);
@@ -57,10 +57,10 @@ export const Item: FC<ItemProps<TArticleItemAny>> = ({ item }) => {
57
57
  }, []);
58
58
 
59
59
  useEffect(() => {
60
- if (!ref.current) return;
61
- const offsetParent = castObject(ref.current.offsetParent, HTMLElement);
60
+ if (!ref) return;
61
+ const offsetParent = castObject(ref.offsetParent, HTMLElement);
62
62
  setParentOffsetTop(offsetParent.offsetTop / window.innerWidth);
63
- }, []);
63
+ }, [ref]);
64
64
 
65
65
  const styles = {
66
66
  transform: `rotate(${angle}deg)`,
@@ -74,7 +74,7 @@ export const Item: FC<ItemProps<TArticleItemAny>> = ({ item }) => {
74
74
  <div
75
75
  suppressHydrationWarning={true}
76
76
  className={`item-${item.id}`}
77
- ref={ref}
77
+ ref={setRef}
78
78
  style={isInitialRef.current ? {} : { ...styles, position: isFixed ? 'fixed': 'absolute' } }
79
79
  >
80
80
  <ItemComponent item={item} />
@@ -1,6 +1,14 @@
1
1
  import { FC, ReactElement } from 'react';
2
- import { getLayoutMediaQuery, getLayoutStyles, TArticleSection, TSectionHeight, SectionHeightMode } from '@cntrl-site/sdk';
2
+ import {
3
+ getLayoutMediaQuery,
4
+ getLayoutStyles,
5
+ TArticleSection,
6
+ TSectionHeight,
7
+ SectionHeightMode,
8
+ CntrlColor
9
+ } from '@cntrl-site/sdk';
3
10
  import { useCntrlContext } from '../provider/useCntrlContext';
11
+ import { useSectionColor } from './useSectionColor';
4
12
 
5
13
  type SectionChild = ReactElement<any, any>;
6
14
 
@@ -11,6 +19,7 @@ interface Props {
11
19
 
12
20
  export const Section: FC<Props> = ({ section, children }) => {
13
21
  const { layouts } = useCntrlContext();
22
+ const backgroundColor = useSectionColor(section.color);
14
23
  const getSectionVisibilityStyles = () => {
15
24
  return layouts
16
25
  .sort((a, b) => a.startsWith - b.startsWith)
@@ -28,7 +37,12 @@ export const Section: FC<Props> = ({ section, children }) => {
28
37
 
29
38
  return (
30
39
  <>
31
- <div className={`section-${section.id}`}>
40
+ <div
41
+ className={`section-${section.id}`}
42
+ style={{
43
+ backgroundColor: backgroundColor
44
+ }}
45
+ >
32
46
  {children}
33
47
  </div>
34
48
  <style jsx>{`
@@ -40,13 +54,6 @@ export const Section: FC<Props> = ({ section, children }) => {
40
54
  }`
41
55
  ))
42
56
  }
43
- ${
44
- getLayoutStyles(layouts, [section.color], ([color]) => (`
45
- .section-${section.id} {
46
- background-color: ${color ? color : 'transparent'};
47
- }`
48
- ))
49
- }
50
57
  ${getSectionVisibilityStyles()}
51
58
  `}</style>
52
59
  </>
@@ -1,11 +1,12 @@
1
- import { FC } from 'react';
2
- import { TImageItem } from '@cntrl-site/sdk';
1
+ import { FC, useMemo } from 'react';
2
+ import { CntrlColor, TImageItem } from '@cntrl-site/sdk';
3
3
  import { ItemProps } from '../Item';
4
4
  import { LinkWrapper } from '../LinkWrapper';
5
5
  import { useFileItem } from './useFileItem';
6
6
 
7
7
  export const ImageItem: FC<ItemProps<TImageItem>> = ({ item }) => {
8
8
  const { radius, strokeWidth, opacity, strokeColor } = useFileItem(item);
9
+ const borderColor = useMemo(() => CntrlColor.parse(strokeColor).toCss(), [strokeColor]);
9
10
  return (
10
11
  <LinkWrapper url={item.link?.url}>
11
12
  <>
@@ -14,7 +15,7 @@ export const ImageItem: FC<ItemProps<TImageItem>> = ({ item }) => {
14
15
  borderRadius: `${radius * 100}vw`,
15
16
  borderWidth: `${strokeWidth * 100}vw`,
16
17
  opacity: `${opacity}`,
17
- borderColor: `${strokeColor}`
18
+ borderColor: `${borderColor}`
18
19
  }}
19
20
  >
20
21
  <img className="image" src={item.commonParams.url} />
@@ -1,20 +1,23 @@
1
- import { FC } from 'react';
2
- import { TRectangleItem } from '@cntrl-site/sdk';
1
+ import { FC, useEffect, useMemo, useState } from 'react';
2
+ import { TRectangleItem, CntrlColor } from '@cntrl-site/sdk';
3
3
  import { ItemProps } from '../Item';
4
4
  import { LinkWrapper } from '../LinkWrapper';
5
5
  import { useRectangleItem } from './useRectangleItem';
6
6
 
7
7
  export const RectangleItem: FC<ItemProps<TRectangleItem>> = ({ item }) => {
8
8
  const { fillColor, radius, strokeWidth, strokeColor } = useRectangleItem(item);
9
+ const backgroundColor = useMemo(() => CntrlColor.parse(fillColor).toCss(), [fillColor]);
10
+ const borderColor = useMemo(() => CntrlColor.parse(strokeColor).toCss(), [strokeColor]);
11
+
9
12
  return (
10
13
  <LinkWrapper url={item.link?.url}>
11
14
  <>
12
15
  <div className={`rectangle-${item.id}`}
13
16
  style={{
14
- backgroundColor: `${fillColor}`,
17
+ backgroundColor: `${backgroundColor}`,
15
18
  borderRadius: `${radius * 100}vw`,
16
19
  borderWidth: `${strokeWidth * 100}vw`,
17
- borderColor: `${strokeColor}`
20
+ borderColor: `${borderColor}`
18
21
  }}
19
22
  />
20
23
  <style jsx>{`
@@ -1,11 +1,12 @@
1
- import { FC } from 'react';
2
- import { TVideoItem } from '@cntrl-site/sdk';
1
+ import { FC, useMemo } from 'react';
2
+ import { CntrlColor, TVideoItem } from '@cntrl-site/sdk';
3
3
  import { ItemProps } from '../Item';
4
4
  import { LinkWrapper } from '../LinkWrapper';
5
5
  import { useFileItem } from './useFileItem';
6
6
 
7
7
  export const VideoItem: FC<ItemProps<TVideoItem>> = ({ item }) => {
8
8
  const { radius, strokeWidth, strokeColor, opacity } = useFileItem(item);
9
+ const borderColor = useMemo(() => CntrlColor.parse(strokeColor).toCss(), [strokeColor]);
9
10
  return (
10
11
  <LinkWrapper url={item.link?.url}>
11
12
  <div className={`video-wrapper-${item.id}`}
@@ -13,7 +14,7 @@ export const VideoItem: FC<ItemProps<TVideoItem>> = ({ item }) => {
13
14
  borderRadius: `${radius * 100}vw`,
14
15
  borderWidth: `${strokeWidth * 100}vw`,
15
16
  opacity: `${opacity}`,
16
- borderColor: `${strokeColor}`
17
+ borderColor: `${borderColor}`
17
18
  }}
18
19
  >
19
20
  <video autoPlay muted loop playsInline className="video">
@@ -1,4 +1,4 @@
1
- import { TImageItem, TVideoItem } from '@cntrl-site/sdk';
1
+ import { CntrlColor, TImageItem, TVideoItem } from '@cntrl-site/sdk';
2
2
  import { useKeyframeValue } from '../../common/useKeyframeValue';
3
3
  import { useCurrentLayout } from '../../common/useCurrentLayout';
4
4
 
@@ -19,7 +19,7 @@ export const useItemSticky = (top: number, parentOffsetTop: number, item: TArtic
19
19
  top,
20
20
  parentOffsetTop
21
21
  ));
22
- }, [top, stickyManager]);
22
+ }, [top, stickyManager, parentOffsetTop]);
23
23
 
24
24
  useEffect(() => {
25
25
  if (!articleRectObserver || !sticky) return;
@@ -1,4 +1,4 @@
1
- import { TRectangleItem } from '@cntrl-site/sdk';
1
+ import { CntrlColor, TRectangleItem } from '@cntrl-site/sdk';
2
2
  import { useKeyframeValue } from '../../common/useKeyframeValue';
3
3
  import { useCurrentLayout } from '../../common/useCurrentLayout';
4
4
 
@@ -33,7 +33,8 @@ export const useRectangleItem = (item: TRectangleItem) => {
33
33
  const layoutParams = item.layoutParams[layoutId];
34
34
  return 'fillColor' in layoutParams ? layoutParams.fillColor : defaultColor;
35
35
  },
36
- (animator, scroll, value) => animator.getColor({ color: value }, scroll).color
36
+ (animator, scroll, value) => animator.getColor({ color: value }, scroll).color,
37
+ [layoutId]
37
38
  );
38
39
  const strokeColor = useKeyframeValue(
39
40
  item,
@@ -42,8 +43,8 @@ export const useRectangleItem = (item: TRectangleItem) => {
42
43
  const layoutParams = item.layoutParams[layoutId];
43
44
  return 'strokeColor' in layoutParams ? layoutParams.strokeColor : defaultColor;
44
45
  },
45
- (animator, scroll, value) => animator.getBorderColor({ color: value }, scroll).color
46
+ (animator, scroll, value) => animator.getBorderColor({ color: value }, scroll).color,
47
+ [layoutId]
46
48
  );
47
-
48
49
  return { fillColor, strokeWidth, radius, strokeColor };
49
50
  };
@@ -0,0 +1,14 @@
1
+ import { useCurrentLayout } from '../common/useCurrentLayout';
2
+ import { useMemo } from 'react';
3
+ import { CntrlColor } from '@cntrl-site/sdk';
4
+
5
+ type LayoutIdentifier = string;
6
+ const DEFAULT_COLOR = 'transparent';
7
+
8
+ export const useSectionColor = (colorData: Record<LayoutIdentifier, string | null>): string => {
9
+ const layoutId = useCurrentLayout();
10
+ return useMemo(() => {
11
+ const layoutColor = colorData[layoutId];
12
+ return !layoutColor ? DEFAULT_COLOR : CntrlColor.parse(layoutColor).toCss();
13
+ }, []);
14
+ };
@@ -1,4 +1,4 @@
1
- import { KeyframeType, TKeyframeValueMap } from '@cntrl-site/sdk';
1
+ import { KeyframeType, TKeyframeValueMap, CntrlColor } from '@cntrl-site/sdk';
2
2
  import { binSearchInsertAt, createInsert } from '../binSearchInsertAt';
3
3
 
4
4
  export interface AnimationData<T extends KeyframeType> {
@@ -84,7 +84,7 @@ export class Animator {
84
84
  }
85
85
  const { start, end } = this.getStartEnd<KeyframeType.Color>(pos, keyframes);
86
86
  return {
87
- color: this.getRgba(start, end, pos)
87
+ color: this.getRangeColor(start, end, pos)
88
88
  };
89
89
  }
90
90
 
@@ -102,7 +102,7 @@ export class Animator {
102
102
  }
103
103
  const { start, end } = this.getStartEnd<KeyframeType.BorderColor>(pos, keyframes);
104
104
  return {
105
- color: this.getRgba(start, end, pos)
105
+ color: this.getRangeColor(start, end, pos)
106
106
  };
107
107
  }
108
108
 
@@ -192,29 +192,19 @@ export class Animator {
192
192
  }
193
193
  }
194
194
 
195
- private getRgba(
195
+ private getRangeColor(
196
196
  start: AnimationData<KeyframeType.Color | KeyframeType.BorderColor>,
197
197
  end: AnimationData<KeyframeType.Color | KeyframeType.BorderColor>,
198
198
  position: number
199
199
  ): string {
200
- const [startR, startG, startB, startA] = parseRgba(start.value.color);
201
- const [endR, endG, endB, endA] = parseRgba(end.value.color);
202
- const r = rangeMap(position, start.position, end.position, startR, endR, true);
203
- const g = rangeMap(position, start.position, end.position, startG, endG, true);
204
- const b = rangeMap(position, start.position, end.position, startB, endB, true);
205
- const a = rangeMap(position, start.position, end.position, startA, endA, true);
206
- return `rgba(${r},${g},${b},${a})`;
200
+ const rangeAmount = rangeMap(position, start.position, end.position, 0, 1, true);
201
+ const startColor = CntrlColor.parse(start.value.color);
202
+ const endColor = CntrlColor.parse(end.value.color);
203
+ const mixedColor = startColor.mix(endColor, rangeAmount);
204
+ return mixedColor.fmt('oklch');
207
205
  }
208
206
  }
209
207
 
210
- const reRgba = /^rgba?\( *(\d+) *, *(\d+) *, *(\d+)(?: *, *(\d+(?:\.\d+)?))? *\)$/i;
211
-
212
- function parseRgba(color: string): [r: number, g: number, b: number, a: number] {
213
- const match = reRgba.exec(color);
214
- if (!match) return [0, 0, 0, 1];
215
- const [, r, g, b, a] = match;
216
- return [parseInt(r, 10), parseInt(g, 10), parseInt(b, 10), a ? parseFloat(a) : NaN];
217
- }
218
208
 
219
209
  function createKeyframesMap(): KeyframesMap {
220
210
  return {
@@ -1,5 +1,6 @@
1
1
  import { ReactElement, ReactNode } from 'react';
2
2
  import {
3
+ CntrlColor,
3
4
  getLayoutMediaQuery,
4
5
  RichText,
5
6
  TextTransform,
@@ -219,7 +220,7 @@ export class RichTextConverter {
219
220
  private static fromDraftToInline(draftStyle: Style): string {
220
221
  const { value, name } = draftStyle;
221
222
  const map: Record<string, Record<string, string | undefined>> = {
222
- 'COLOR': { 'color': value },
223
+ 'COLOR': { 'color': getResolvedValue(value, name) },
223
224
  'TYPEFACE': { 'font-family': `${value}` },
224
225
  'FONTSTYLE': value ? { ...FontStyles[value] } : {},
225
226
  'FONTWEIGHT': { 'font-weight': value },
@@ -250,3 +251,8 @@ function groupBy<I>(items: I[], getKey: (item: I) => PropertyKey): Record<Proper
250
251
  }
251
252
  return groups;
252
253
  }
254
+
255
+ function getResolvedValue(value: string | undefined, name: string) {
256
+ if (name !== 'COLOR') return value;
257
+ return value ? CntrlColor.parse(value).toCss() : value;
258
+ }
@@ -1,4 +1,4 @@
1
- import { getLayoutMediaQuery, TLayout, TTypePresets } from '@cntrl-site/sdk';
1
+ import { getLayoutMediaQuery, TLayout, TTypePresets, CntrlColor } from '@cntrl-site/sdk';
2
2
 
3
3
  const reEmptyLines = /^\s*\n/gm;
4
4
 
@@ -18,7 +18,7 @@ ${getLayoutMediaQuery(l.id, sorted)} {
18
18
  line-height: ${p.layoutParams[l.id].lineHeight * 100}vw;
19
19
  letter-spacing: ${p.layoutParams[l.id].letterSpacing * 100}vw;
20
20
  word-spacing: ${p.layoutParams[l.id].wordSpacing * 100}vw;
21
- color: ${p.layoutParams[l.id].color};
21
+ color: ${CntrlColor.parse(p.layoutParams[l.id].color).toCss()};
22
22
  }
23
23
  }`)).join('\n')}`)).join('\n')}`);
24
24
  return stylesStr.replace(reEmptyLines, '');
Binary file