@financial-times/qanda-ui 0.0.1-beta.8 → 0.0.1-beta.9

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.
@@ -8,11 +8,69 @@ const cp_content_pipeline_ui_1 = require("@financial-times/cp-content-pipeline-u
8
8
  require("../Expander/index");
9
9
  const index_1 = __importDefault(require("../Expander/index"));
10
10
  const Author_1 = __importDefault(require("../Author"));
11
+ const react_1 = require("react");
11
12
  function renderTime(publishedDate) {
12
13
  const date = new Date(publishedDate);
13
14
  return `${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`;
14
15
  }
16
+ // Get shadow color based on factor
17
+ function interpolateColor(factor, colorStart = 'ccc1b7', colorEnd = '4d4845', alphaStart = 0.5, alphaEnd = 0.85) {
18
+ const hexToRgb = (hex) => hex.match(/[0-9a-f]{2}/g).map((x) => parseInt(x, 16));
19
+ const startRgb = hexToRgb(colorStart);
20
+ const endRgb = hexToRgb(colorEnd);
21
+ const rgb = startRgb.map((val, i) => Math.round(val + (endRgb[i] - val) * factor));
22
+ const alpha = alphaStart + factor * (alphaEnd - alphaStart);
23
+ return `rgba(${rgb.join(', ')}, ${alpha})`;
24
+ }
15
25
  function QandaBlock({ id, body, children, byline, subtitle, showAnswerTime = false, }) {
26
+ (0, react_1.useEffect)(() => {
27
+ let currentBubble = null;
28
+ const factorRef = { current: 0 };
29
+ let animationFrameId;
30
+ const observer = new IntersectionObserver((entries) => {
31
+ entries.forEach((entry) => {
32
+ if (entry.isIntersecting) {
33
+ if (currentBubble !== entry.target) {
34
+ factorRef.current = 0;
35
+ }
36
+ currentBubble = entry.target;
37
+ }
38
+ });
39
+ }, {
40
+ root: null,
41
+ rootMargin: '-50% 0px -50% 0px',
42
+ threshold: 0,
43
+ });
44
+ const comments = document.querySelectorAll('.qanda-block__comment');
45
+ comments.forEach((comment) => observer.observe(comment));
46
+ const animate = () => {
47
+ const centerY = window.innerHeight / 2;
48
+ if (currentBubble) {
49
+ const rect = currentBubble.getBoundingClientRect();
50
+ const commentCenterY = rect.top + rect.height / 2;
51
+ const distanceRatio = Math.min(Math.abs(centerY - commentCenterY) / centerY, 1);
52
+ const targetFactor = (1 - distanceRatio) ** 3;
53
+ factorRef.current += (targetFactor - factorRef.current) * 0.1;
54
+ const scale = 1 + 0.04 * factorRef.current;
55
+ const shadow = interpolateColor(factorRef.current);
56
+ currentBubble.style.transform = `scale(${scale})`;
57
+ currentBubble.style.filter = `drop-shadow(0px 2px 8px ${shadow})`;
58
+ if (factorRef.current < 0.001 && distanceRatio > 0.95) {
59
+ currentBubble.removeAttribute('style');
60
+ currentBubble = null;
61
+ factorRef.current = 0;
62
+ }
63
+ }
64
+ animationFrameId = requestAnimationFrame(animate);
65
+ };
66
+ animationFrameId = requestAnimationFrame(animate);
67
+ window.addEventListener('resize', animate);
68
+ return () => {
69
+ cancelAnimationFrame(animationFrameId);
70
+ window.removeEventListener('resize', animate);
71
+ observer.disconnect();
72
+ };
73
+ }, []);
16
74
  return ((0, jsx_runtime_1.jsxs)("div", { className: "qanda-block", children: [(0, jsx_runtime_1.jsxs)("div", { className: "qanda-block__comment qanda-block__question", id: id, "data-testid": `qanda-block__question-${id}`, "data-trackable": "liveqa_question", children: [subtitle && ((0, jsx_runtime_1.jsx)("div", { className: "o3-type-headline-sm qanda-block__question-subtitle", children: subtitle })), (0, jsx_runtime_1.jsx)("div", { className: "o3-type-body-highlight qanda-block__comment-byline", children: (0, jsx_runtime_1.jsx)(cp_content_pipeline_ui_1.Byline, { structuredContent: byline, showEditedBy: false }) }), (0, jsx_runtime_1.jsx)("div", { className: "o3-type-body-base qanda-block__comment-text", children: (0, jsx_runtime_1.jsx)(index_1.default, { className: "qanda-block__text", expandLabel: "Expand question", collapseLabel: "Collapse question", id: id, children: (0, jsx_runtime_1.jsx)(cp_content_pipeline_ui_1.RichText, { structuredContent: body.structured }) }) })] }, id), children?.map((child) => child.body && ((0, jsx_runtime_1.jsxs)("div", { className: "qanda-block__comment qanda-block__answer", "data-testid": `qanda-block__answer-${child.id}`, "data-trackable": "liveqa_answer", children: [(0, jsx_runtime_1.jsxs)("div", { className: "qanda-block__answer-header", children: [(0, jsx_runtime_1.jsx)("div", { className: "o3-type-body-highlight qanda-block__comment-byline", children: child.author ? ((0, jsx_runtime_1.jsx)(Author_1.default, { byline: child.byline, headshot: child.author.headshot, prefLabel: child.author.prefLabel, role: child.author.role, streamPage: child.author.streamPage })) : ((0, jsx_runtime_1.jsx)(cp_content_pipeline_ui_1.Byline, { structuredContent: child.byline, showEditedBy: false })) }), showAnswerTime && ((0, jsx_runtime_1.jsx)("span", { className: "o3-type-detail", children: renderTime(child.publishedDate) }))] }), (0, jsx_runtime_1.jsx)("div", { className: "o3-type-body-base qanda-block__comment-text", children: (0, jsx_runtime_1.jsx)(index_1.default, { className: "qanda-block__text", expandLabel: "Expand answer", collapseLabel: "Collapse answer", id: id, children: (0, jsx_runtime_1.jsx)(cp_content_pipeline_ui_1.RichText, { structuredContent: child.body.structured }) }) })] }, child.id)))] }));
17
75
  }
18
76
  exports.default = QandaBlock;
@@ -3,11 +3,69 @@ import { RichText, Byline } from '@financial-times/cp-content-pipeline-ui';
3
3
  import '../Expander/index';
4
4
  import Expander from '../Expander/index';
5
5
  import Author from '../Author';
6
+ import { useEffect } from 'react';
6
7
  function renderTime(publishedDate) {
7
8
  const date = new Date(publishedDate);
8
9
  return `${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`;
9
10
  }
11
+ // Get shadow color based on factor
12
+ function interpolateColor(factor, colorStart = 'ccc1b7', colorEnd = '4d4845', alphaStart = 0.5, alphaEnd = 0.85) {
13
+ const hexToRgb = (hex) => hex.match(/[0-9a-f]{2}/g).map((x) => parseInt(x, 16));
14
+ const startRgb = hexToRgb(colorStart);
15
+ const endRgb = hexToRgb(colorEnd);
16
+ const rgb = startRgb.map((val, i) => Math.round(val + (endRgb[i] - val) * factor));
17
+ const alpha = alphaStart + factor * (alphaEnd - alphaStart);
18
+ return `rgba(${rgb.join(', ')}, ${alpha})`;
19
+ }
10
20
  function QandaBlock({ id, body, children, byline, subtitle, showAnswerTime = false, }) {
21
+ useEffect(() => {
22
+ let currentBubble = null;
23
+ const factorRef = { current: 0 };
24
+ let animationFrameId;
25
+ const observer = new IntersectionObserver((entries) => {
26
+ entries.forEach((entry) => {
27
+ if (entry.isIntersecting) {
28
+ if (currentBubble !== entry.target) {
29
+ factorRef.current = 0;
30
+ }
31
+ currentBubble = entry.target;
32
+ }
33
+ });
34
+ }, {
35
+ root: null,
36
+ rootMargin: '-50% 0px -50% 0px',
37
+ threshold: 0,
38
+ });
39
+ const comments = document.querySelectorAll('.qanda-block__comment');
40
+ comments.forEach((comment) => observer.observe(comment));
41
+ const animate = () => {
42
+ const centerY = window.innerHeight / 2;
43
+ if (currentBubble) {
44
+ const rect = currentBubble.getBoundingClientRect();
45
+ const commentCenterY = rect.top + rect.height / 2;
46
+ const distanceRatio = Math.min(Math.abs(centerY - commentCenterY) / centerY, 1);
47
+ const targetFactor = (1 - distanceRatio) ** 3;
48
+ factorRef.current += (targetFactor - factorRef.current) * 0.1;
49
+ const scale = 1 + 0.04 * factorRef.current;
50
+ const shadow = interpolateColor(factorRef.current);
51
+ currentBubble.style.transform = `scale(${scale})`;
52
+ currentBubble.style.filter = `drop-shadow(0px 2px 8px ${shadow})`;
53
+ if (factorRef.current < 0.001 && distanceRatio > 0.95) {
54
+ currentBubble.removeAttribute('style');
55
+ currentBubble = null;
56
+ factorRef.current = 0;
57
+ }
58
+ }
59
+ animationFrameId = requestAnimationFrame(animate);
60
+ };
61
+ animationFrameId = requestAnimationFrame(animate);
62
+ window.addEventListener('resize', animate);
63
+ return () => {
64
+ cancelAnimationFrame(animationFrameId);
65
+ window.removeEventListener('resize', animate);
66
+ observer.disconnect();
67
+ };
68
+ }, []);
11
69
  return (_jsxs("div", { className: "qanda-block", children: [_jsxs("div", { className: "qanda-block__comment qanda-block__question", id: id, "data-testid": `qanda-block__question-${id}`, "data-trackable": "liveqa_question", children: [subtitle && (_jsx("div", { className: "o3-type-headline-sm qanda-block__question-subtitle", children: subtitle })), _jsx("div", { className: "o3-type-body-highlight qanda-block__comment-byline", children: _jsx(Byline, { structuredContent: byline, showEditedBy: false }) }), _jsx("div", { className: "o3-type-body-base qanda-block__comment-text", children: _jsx(Expander, { className: "qanda-block__text", expandLabel: "Expand question", collapseLabel: "Collapse question", id: id, children: _jsx(RichText, { structuredContent: body.structured }) }) })] }, id), children?.map((child) => child.body && (_jsxs("div", { className: "qanda-block__comment qanda-block__answer", "data-testid": `qanda-block__answer-${child.id}`, "data-trackable": "liveqa_answer", children: [_jsxs("div", { className: "qanda-block__answer-header", children: [_jsx("div", { className: "o3-type-body-highlight qanda-block__comment-byline", children: child.author ? (_jsx(Author, { byline: child.byline, headshot: child.author.headshot, prefLabel: child.author.prefLabel, role: child.author.role, streamPage: child.author.streamPage })) : (_jsx(Byline, { structuredContent: child.byline, showEditedBy: false })) }), showAnswerTime && (_jsx("span", { className: "o3-type-detail", children: renderTime(child.publishedDate) }))] }), _jsx("div", { className: "o3-type-body-base qanda-block__comment-text", children: _jsx(Expander, { className: "qanda-block__text", expandLabel: "Expand answer", collapseLabel: "Collapse answer", id: id, children: _jsx(RichText, { structuredContent: child.body.structured }) }) })] }, child.id)))] }));
12
70
  }
13
71
  export default QandaBlock;
package/dist/qanda.scss CHANGED
@@ -532,6 +532,8 @@ $app-header-color: #007acc;
532
532
  .qanda-block__comment {
533
533
  padding: var(--o3-spacing-s) var(--o3-spacing-2xs);
534
534
  position: relative;
535
+ filter: drop-shadow(0px 2px 8px #ccc1b7);
536
+ will-change: filter;
535
537
  }
536
538
 
537
539
  .qanda-block__question {
@@ -3,5 +3,5 @@ import '../Expander/index';
3
3
  type QandaBlockProps = Comment & {
4
4
  showAnswerTime: boolean;
5
5
  };
6
- declare function QandaBlock({ id, body, children, byline, subtitle, showAnswerTime, }: QandaBlockProps): import("react-dom/src").JSX.Element;
6
+ declare function QandaBlock({ id, body, children, byline, subtitle, showAnswerTime, }: QandaBlockProps): import("react").JSX.Element;
7
7
  export default QandaBlock;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@financial-times/qanda-ui",
3
- "version": "0.0.1-beta.8",
3
+ "version": "0.0.1-beta.9",
4
4
  "description": "Components for the Live Q&A UI",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",