@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
|
@@ -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
|
|
6
|
+
declare function QandaBlock({ id, body, children, byline, subtitle, showAnswerTime, }: QandaBlockProps): import("react").JSX.Element;
|
|
7
7
|
export default QandaBlock;
|