Skip to content
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
6653bed
test(pdf): pin document context state behavior
dev-rb Sep 17, 2026
f8c5e79
refactor(pdf): localize narrow document state
dev-rb Sep 17, 2026
2c3219f
test(pdf): pin placeable edit behavior
dev-rb Sep 17, 2026
c6999ea
refactor(pdf): extract document model authority
dev-rb Sep 17, 2026
bb57f3c
refactor(pdf): extract persistence authority
dev-rb Sep 17, 2026
76c9ba2
refactor(pdf): extract tabs authority
dev-rb Sep 17, 2026
ffa3475
refactor(pdf): extract navigation authority
dev-rb Sep 17, 2026
63da226
refactor(pdf): extract viewer runtime
dev-rb Sep 17, 2026
9bb43cd
refactor(pdf): project viewer events at boundary
dev-rb Sep 17, 2026
ef0d0d0
refactor(pdf): localize comment layout state
dev-rb Sep 17, 2026
93ee739
refactor(pdf): extract definitions authority
dev-rb Sep 17, 2026
9e39167
test(pdf): pin outline projection behavior
dev-rb Sep 17, 2026
609c7a1
refactor(pdf): replace dead outline reducer
dev-rb Sep 17, 2026
22a6a76
refactor(pdf): extract interaction authorities
dev-rb Sep 17, 2026
45c3ce2
test(pdf): pin annotation projections
dev-rb Sep 17, 2026
c1cedb6
refactor(pdf): delete legacy state buckets
dev-rb Sep 17, 2026
21806e3
refactor(pdf): flatten interaction context API
dev-rb Sep 17, 2026
1fc7644
refactor(pdf): separate viewer context
dev-rb Sep 17, 2026
e658823
refactor(pdf): split navigation state ownership
dev-rb Sep 17, 2026
dcbb144
refactor(pdf): remove interaction state aggregate
dev-rb Sep 17, 2026
52d8978
fix(pdf): prevent repeated comment scrolling
dev-rb Sep 18, 2026
f2f6d52
fix(pdf): layer comments above side panels
dev-rb Sep 18, 2026
ba8b09e
fix(pdf): stabilize margin comment interactions
dev-rb Sep 18, 2026
dac0c8a
refactor(pdf): preserve popup UI during cleanup
dev-rb Sep 18, 2026
53fe20a
Merge remote-tracking branch 'origin/main' into rahul/refactor-pdf-bl…
dev-rb Sep 20, 2026
e79f43d
fix(pdf): give comment drafts unique identities
dev-rb Sep 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
147 changes: 0 additions & 147 deletions apps/web/src/features/block-pdf/PdfViewer/TermDataStore.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import type Term from '../model/Term';
import {
usePopupContextUpdate,
usePopupStore,
} from '../signal/definitionPopup';
import { useIsPopup } from '../signal/pdfViewer';
import { usePopupContextUpdate, usePopupStore } from '../store/definitionPopup';
import { DefinitionLookup } from './DefinitionLookup/index';

interface IProps {
Expand Down
5 changes: 1 addition & 4 deletions apps/web/src/features/block-pdf/component/Block.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { SidePanel } from '@components/app/side-panel';
import { blockDataSignalAs, useBlockId, useIsNestedBlock } from '@core/block';
import { DocumentBlockContainer } from '@core/component/DocumentBlockContainer';
import { createMethodRegistration } from '@core/orchestrator';
import { blockHotkeyScopeSignal } from '@core/signal/blockElement';
import { blockHandleSignal, blockMetadataSignal } from '@core/signal/load';
import {
useCanComment,
Expand Down Expand Up @@ -52,7 +51,6 @@ export default function BlockPdf() {
viewLocation={data()?.viewLocation}
modificationData={data()?.documentMetadata.modificationData}
isNested={isNested}
hotkeyScope={blockHotkeyScopeSignal.get()}
portalScope="block"
permissions={{
canComment: canComment(),
Expand All @@ -70,7 +68,6 @@ export default function BlockPdf() {

function PdfBlockContent() {
const pdf = usePdfDocument();
const [showTabBar] = pdf.state.signals.showTabBar;

return (
<ModalsProvider>
Expand All @@ -79,7 +76,7 @@ function PdfBlockContent() {
<PdfSidePanelSections />
<div class="flex size-full min-w-0 flex-col overflow-hidden">
<TopBar />
<Show when={showTabBar()}>
<Show when={pdf.tabs.isVisible()}>
<div class="flex px-2 justify-between min-h-11 items-center gap-2">
<div class="overflow-x-auto overflow-y-hidden grow customScrollbar w-0">
<Tabs />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,27 +1,25 @@
import { Accordion } from '@kobalte/core/accordion';
import { cn } from '@ui';
import Scrollbars from 'solid-custom-scrollbars';
import { createMemo, createSignal, For, type JSX } from 'solid-js';
import { createMemo, createSignal, For, type JSX, Show } from 'solid-js';
import { styled } from 'solid-styled-components';
import { usePdfDocument } from '../../context/pdf-document-context';
import {
Color,
determineFormat,
hexToRgb,
type IColor,
} from '../../model/Color';
import type Section from '../../model/Section';
import type Term from '../../model/Term';
import { keyedTermDataStore } from '../../PdfViewer/TermDataStore';
import { useTableOfContentsValue } from '../../store/tableOfContents';
import { CoParseClassName } from '../../type/coParse';
import { decodeDefinitionText } from '../../util/definitionText';
import TocUtils from '../../util/TocUtils';
import { OpenRefInNewTabIcon } from './OpenRefInNewTabIcon';
import {
AccordionText,
accordionCardStyles,
accordionCollapseStyles,
accordionHeadStyles,
decodeString,
FONT_SIZE,
LINE_HEIGHT,
} from './shared';
Expand All @@ -36,6 +34,7 @@ const htmlSpecialEntities = [
['&lt;', '<'],
['&gt;', '>'],
];
const SECTION_MAX_CHARS = 80;

const BootstrapCard = styled.div`
width: 100%;
Expand All @@ -60,7 +59,6 @@ const DefinitionText = styled.p<{ truncated: boolean }>`
margin: 0;
`;

// removed hover styles because they were being applied on individual characters
const HoverText = styled.span<{
color: string;
hoverColor: string;
Expand All @@ -70,8 +68,6 @@ const HoverText = styled.span<{
cursor: pointer;
`;

const SECTION_MAX_CHARS = 80;

function filterUniqueTerms(terms: (Term | null)[]): Term[] {
let uniqueObj: { [key: string]: Term } = {};
terms.forEach((t) => {
Expand All @@ -84,33 +80,37 @@ function filterUniqueTerms(terms: (Term | null)[]): Term[] {
return uniqueTerms;
}

function computeRelatedTerms(term: Term): Term[] {
const store = keyedTermDataStore();
if (!store) return [];
let simTerms: (Term | null)[] = term.sims.map((t) => store.get(t));
function truncateSectionDescriptor(descriptor: string): string {
if (descriptor.length <= SECTION_MAX_CHARS) return descriptor;
return `${descriptor.substring(0, SECTION_MAX_CHARS)}...`;
}

function computeRelatedTerms(
term: Term,
getTerm: (id: string) => Term | null
): Term[] {
let simTerms: (Term | null)[] = term.sims.map(getTerm);
simTerms.unshift(term);
return filterUniqueTerms(simTerms);
}

interface IProps {
truncated: boolean;
term: Term;
getTerm: (id: string) => Term | null;
onClick: JSX.EventHandler<HTMLElement, MouseEvent>;
setSection: (section: Section | null) => void;
setHoveredDOMRect: (hoveredDOMRect: DOMRect | null) => void;
}

export function DefinitionsAccordion(props: IProps) {
const tableOfContentsContext = useTableOfContentsValue();
const terms = createMemo(() => computeRelatedTerms(props.term));
const idToSectionMap = usePdfDocument().outline.sectionReferenceMap;
const terms = createMemo(() =>
computeRelatedTerms(props.term, props.getTerm)
);

/**
* Generate the span's making up the definition text, including definition and section links
*/
const constructSpans = (elArr: ChildNode[]) => {
const spans = elArr.map((el, _idx) => {
const element = el as Element;
const decodedString = decodeString(element);
const decodedString = decodeDefinitionText(element);
const className = element.getAttribute('class');
const isSection = className === CoParseClassName.SectionReference;
const decodedStringArray = decodedString.split(COLORDELIMITER);
Expand Down Expand Up @@ -139,7 +139,6 @@ export function DefinitionsAccordion(props: IProps) {
snippetText = snippetText.replaceAll(entity[0], entity[1]);
});
if (isSection || className === CoParseClassName.TermReference) {
// Either a section reference or a term reference
const classID = element.getAttribute(isSection ? 'secId' : 'defId');
const id = `${className}_${classID}`;
content.push(
Expand Down Expand Up @@ -195,7 +194,6 @@ export function DefinitionsAccordion(props: IProps) {
}
});
} else if (isSection || className === CoParseClassName.TermReference) {
// Either a section reference or a term reference
const classID = element.getAttribute(isSection ? 'secId' : 'defId');
const id = `${className}_${classID}`;
return (
Expand All @@ -211,14 +209,12 @@ export function DefinitionsAccordion(props: IProps) {
</HoverText>
);
}
// Regular text
if (content.length === 0) {
return (
<span style={{ 'white-space': 'pre-wrap' }}>{decodedString}</span>
);
}

// Regular text
return <span>{content}</span>;
});
return spans;
Expand All @@ -243,11 +239,12 @@ export function DefinitionsAccordion(props: IProps) {
n.nodeName.includes('span')
);
const spans = constructSpans(elArr);
const nearestSection = TocUtils.getNearestSection({
page: t.pageNum,
yPos: t.yPos,
pageToSectionMap: tableOfContentsContext().pageToSectionMap,
});
const nearestSection = () =>
TocUtils.getNearestSection({
page: t.pageNum,
yPos: t.yPos,
idToSectionMap: idToSectionMap(),
});

return (
<Accordion.Item value={'definitionCard' + idx()}>
Expand All @@ -262,17 +259,20 @@ export function DefinitionsAccordion(props: IProps) {
}}
>
<AccordionText>
{nearestSection
? `In ${
nearestSection.fullDescriptor.length >
SECTION_MAX_CHARS
? nearestSection.fullDescriptor.substring(
0,
SECTION_MAX_CHARS
) + '...'
: nearestSection.fullDescriptor
} on page ${t.pageNum + 1} `
: `On page ${t.pageNum + 1}`}
<Show
when={nearestSection()}
fallback={<>On page {t.pageNum + 1}</>}
>
{(section) => (
<>
In{' '}
{truncateSectionDescriptor(
section().fullDescriptor
)}{' '}
on page {t.pageNum + 1}
</>
)}
</Show>
</AccordionText>
<OpenRefInNewTabIcon reference={t} term={props.term} />
</button>
Expand Down
Loading
Loading