Spoilers: Keep non-overlapping bodyRanges separate
This commit is contained in:
parent
1c9651f557
commit
269cd9b51d
3 changed files with 55 additions and 20 deletions
|
@ -278,7 +278,19 @@ export function FormattingSpoiler(): JSX.Element {
|
||||||
bodyRanges: [
|
bodyRanges: [
|
||||||
{
|
{
|
||||||
start: 8,
|
start: 8,
|
||||||
length: 89,
|
length: 60,
|
||||||
|
style: BodyRange.Style.SPOILER,
|
||||||
|
},
|
||||||
|
// This is touching, but not overlapping; they should not reveal together
|
||||||
|
{
|
||||||
|
start: 68,
|
||||||
|
length: 29,
|
||||||
|
style: BodyRange.Style.SPOILER,
|
||||||
|
},
|
||||||
|
// Note: in overlaps, the last spoiler wins
|
||||||
|
{
|
||||||
|
start: 94,
|
||||||
|
length: 6,
|
||||||
style: BodyRange.Style.SPOILER,
|
style: BodyRange.Style.SPOILER,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -322,7 +334,11 @@ export function FormattingSpoiler(): JSX.Element {
|
||||||
<hr />
|
<hr />
|
||||||
<MessageBody {...props} disableLinks />
|
<MessageBody {...props} disableLinks />
|
||||||
<hr />
|
<hr />
|
||||||
<MessageBody {...props} isSpoilerExpanded={{}} />
|
<MessageBody
|
||||||
|
{...props}
|
||||||
|
onExpandSpoiler={() => null}
|
||||||
|
isSpoilerExpanded={{}}
|
||||||
|
/>
|
||||||
<hr />
|
<hr />
|
||||||
<MessageBody {...props} disableLinks isSpoilerExpanded={{}} />
|
<MessageBody {...props} disableLinks isSpoilerExpanded={{}} />
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -75,8 +75,22 @@ export function MessageTextRenderer({
|
||||||
|
|
||||||
// Create range tree, dropping bodyRanges that don't apply. Read More means truncated
|
// Create range tree, dropping bodyRanges that don't apply. Read More means truncated
|
||||||
// strings.
|
// strings.
|
||||||
|
let spoilerCount = 0;
|
||||||
const tree = sortedRanges.reduce<ReadonlyArray<RangeNode>>(
|
const tree = sortedRanges.reduce<ReadonlyArray<RangeNode>>(
|
||||||
(acc, range) => {
|
(acc, range) => {
|
||||||
|
if (
|
||||||
|
BodyRange.isFormatting(range) &&
|
||||||
|
range.style === BodyRange.Style.SPOILER
|
||||||
|
) {
|
||||||
|
spoilerCount += 1;
|
||||||
|
return insertRange(
|
||||||
|
{
|
||||||
|
...range,
|
||||||
|
spoilerId: spoilerCount,
|
||||||
|
},
|
||||||
|
acc
|
||||||
|
);
|
||||||
|
}
|
||||||
if (range.start < textLength) {
|
if (range.start < textLength) {
|
||||||
return insertRange(range, acc);
|
return insertRange(range, acc);
|
||||||
}
|
}
|
||||||
|
@ -139,7 +153,7 @@ function renderNode({
|
||||||
|
|
||||||
if (node.isSpoiler && node.spoilerChildren?.length) {
|
if (node.isSpoiler && node.spoilerChildren?.length) {
|
||||||
const isSpoilerHidden = Boolean(
|
const isSpoilerHidden = Boolean(
|
||||||
node.isSpoiler && !isSpoilerExpanded[node.spoilerIndex || 0]
|
node.isSpoiler && !isSpoilerExpanded[node.spoilerId || 0]
|
||||||
);
|
);
|
||||||
const content = node.spoilerChildren?.map(spoilerNode =>
|
const content = node.spoilerChildren?.map(spoilerNode =>
|
||||||
renderNode({
|
renderNode({
|
||||||
|
@ -193,7 +207,7 @@ function renderNode({
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
onExpandSpoiler({
|
onExpandSpoiler({
|
||||||
...isSpoilerExpanded,
|
...isSpoilerExpanded,
|
||||||
[node.spoilerIndex || 0]: true,
|
[node.spoilerId || 0]: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -209,7 +223,7 @@ function renderNode({
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
onExpandSpoiler?.({
|
onExpandSpoiler?.({
|
||||||
...isSpoilerExpanded,
|
...isSpoilerExpanded,
|
||||||
[node.spoilerIndex || 0]: true,
|
[node.spoilerId || 0]: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,7 @@ export namespace BodyRange {
|
||||||
};
|
};
|
||||||
export type Formatting = {
|
export type Formatting = {
|
||||||
style: Style;
|
style: Style;
|
||||||
|
spoilerId?: number;
|
||||||
};
|
};
|
||||||
export type DisplayOnly = {
|
export type DisplayOnly = {
|
||||||
displayStyle: DisplayStyle;
|
displayStyle: DisplayStyle;
|
||||||
|
@ -356,8 +357,8 @@ export type DisplayNode = {
|
||||||
// DisplayOnly
|
// DisplayOnly
|
||||||
isKeywordHighlight?: boolean;
|
isKeywordHighlight?: boolean;
|
||||||
|
|
||||||
// Only for spoilers, only to represent contiguous groupings
|
// Only for spoilers, only to make sure we honor original spoiler breakdown
|
||||||
spoilerIndex?: number;
|
spoilerId?: number;
|
||||||
spoilerChildren?: ReadonlyArray<DisplayNode>;
|
spoilerChildren?: ReadonlyArray<DisplayNode>;
|
||||||
};
|
};
|
||||||
type PartialDisplayNode = Omit<
|
type PartialDisplayNode = Omit<
|
||||||
|
@ -381,7 +382,7 @@ function rangeToPartialNode(
|
||||||
return { isMonospace: true };
|
return { isMonospace: true };
|
||||||
}
|
}
|
||||||
if (range.style === BodyRange.Style.SPOILER) {
|
if (range.style === BodyRange.Style.SPOILER) {
|
||||||
return { isSpoiler: true };
|
return { isSpoiler: true, spoilerId: range.spoilerId };
|
||||||
}
|
}
|
||||||
if (range.style === BodyRange.Style.STRIKETHROUGH) {
|
if (range.style === BodyRange.Style.STRIKETHROUGH) {
|
||||||
return { isStrikethrough: true };
|
return { isStrikethrough: true };
|
||||||
|
@ -482,25 +483,29 @@ export function groupContiguousSpoilers(
|
||||||
const result: Array<DisplayNode> = [];
|
const result: Array<DisplayNode> = [];
|
||||||
|
|
||||||
let spoilerContainer: DisplayNode | undefined;
|
let spoilerContainer: DisplayNode | undefined;
|
||||||
let spoilerIndex = 0;
|
|
||||||
|
|
||||||
nodes.forEach(node => {
|
nodes.forEach(node => {
|
||||||
if (node.isSpoiler) {
|
if (node.isSpoiler) {
|
||||||
if (!spoilerContainer) {
|
if (
|
||||||
spoilerContainer = {
|
spoilerContainer &&
|
||||||
...node,
|
isNumber(spoilerContainer.spoilerId) &&
|
||||||
spoilerIndex,
|
spoilerContainer.spoilerId === node.spoilerId
|
||||||
isSpoiler: true,
|
) {
|
||||||
spoilerChildren: [],
|
|
||||||
};
|
|
||||||
spoilerIndex += 1;
|
|
||||||
result.push(spoilerContainer);
|
|
||||||
}
|
|
||||||
if (spoilerContainer) {
|
|
||||||
spoilerContainer.spoilerChildren = [
|
spoilerContainer.spoilerChildren = [
|
||||||
...(spoilerContainer.spoilerChildren || []),
|
...(spoilerContainer.spoilerChildren || []),
|
||||||
node,
|
node,
|
||||||
];
|
];
|
||||||
|
} else {
|
||||||
|
spoilerContainer = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!spoilerContainer) {
|
||||||
|
spoilerContainer = {
|
||||||
|
...node,
|
||||||
|
isSpoiler: true,
|
||||||
|
spoilerChildren: [node],
|
||||||
|
};
|
||||||
|
result.push(spoilerContainer);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
spoilerContainer = undefined;
|
spoilerContainer = undefined;
|
||||||
|
|
Loading…
Reference in a new issue