Skip to content

Commit 4fa1343

Browse files
authored
Create continuous scroll view (#40)
* feat: add interlinearizer.continuousScroll project setting with toggle UI * feat: extract SegmentView component with token-chip and baseline-text display modes * Add ContinuousView core (continuous token strip, smooth incremental arrows, boundary/fade behavior) * Compose ContinuousView above chapter rows and finalize conditional display rules * Propagate verse change from ContinuousView arrow navigation to scroll group * Add PhraseBox-based phrase navigation and clickable focus behavior * Use optimistic continuous-scroll state across webview * Fix bugs * Refine continuous view behavior and stabilize web-view tests * Extract book data into hook and restructure sticky layout - Create useInterlinearizerBookData hook to consolidate USJ fetch, tokenization, and state - Remove ProjectBookFetcher component entirely - Simplify root rendering to directly use hook output - Move ContinuousView into toolbar sticky container to prevent overlap - Remove ResizeObserver and stickyTopOffset complexity - Clean up jest.setup.ts mock (no longer needed) * Add comprehensive web view, hook, and component tests * Add border below ContinuousView * Memoize segment onClick * Memoize PhraseBox, SegmentView, TokenChip * Avoid first-load extra fire; Tidy code * Add timeout if setting-save fails * Extract settings hook and add testing * Complete Web View coverage * Complete ContinuousView test coverage * Replace left/right with prev/next for RTL support * Fix arrows and RTL support * Show loading while waiting for setting * Use existing type * Split up main Web View into pieces * Complete ContinuousView coverage * Add setting type * Smooth-scroll for internal clicks * Remove useless setting type specification * Add comment * Clean up dead code; Fix deps * Remove excess test setup * Improve test * Consolidate tests * Cover missing branch * Stabilize toggle * Simplify layout
1 parent 594b0bd commit 4fa1343

27 files changed

Lines changed: 3250 additions & 562 deletions

__mocks__/platform-bible-react.tsx

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,41 @@ export function BookChapterControl({
8282
</div>
8383
);
8484
}
85+
86+
export function Switch({
87+
checked,
88+
disabled,
89+
id,
90+
onCheckedChange,
91+
}: Readonly<{
92+
checked?: boolean;
93+
disabled?: boolean;
94+
id?: string;
95+
onCheckedChange?: (checked: boolean) => void;
96+
}>): ReactElement {
97+
return (
98+
<input
99+
checked={checked ?? false}
100+
disabled={disabled}
101+
id={id}
102+
onChange={(e) => onCheckedChange?.(e.target.checked)}
103+
type="checkbox"
104+
/>
105+
);
106+
}
107+
108+
export function Label({
109+
children,
110+
className,
111+
htmlFor,
112+
}: Readonly<{
113+
children?: ReactNode;
114+
className?: string;
115+
htmlFor?: string;
116+
}>): ReactElement {
117+
return (
118+
<label className={className} htmlFor={htmlFor}>
119+
{children}
120+
</label>
121+
);
122+
}

contributions/localizedStrings.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@
44
"en": {
55
"%interlinearizer_dialog_open_title%": "Open Interlinearizer",
66
"%interlinearizer_dialog_open_prompt%": "Choose a project to open in the Interlinearizer:",
7-
"%interlinearizer_openForProject%": "Open Interlinearizer for this Project"
7+
"%interlinearizer_openForProject%": "Open Interlinearizer for this Project",
8+
"%interlinearizer_projectSettings_title%": "Interlinearizer",
9+
"%interlinearizer_projectSettings_continuousScroll%": "Continuous Scroll",
10+
"%interlinearizer_projectSettings_continuousScrollDescription%": "Display tokens in a continuous horizontal scroll strip instead of chapter-segmented rows",
11+
"%interlinearizer_continuousScrollToggle%": "Continuous Scroll"
812
}
913
}
1014
}

contributions/projectSettings.json

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,12 @@
1-
[]
1+
[
2+
{
3+
"label": "%interlinearizer_projectSettings_title%",
4+
"properties": {
5+
"interlinearizer.continuousScroll": {
6+
"label": "%interlinearizer_projectSettings_continuousScroll%",
7+
"description": "%interlinearizer_projectSettings_continuousScrollDescription%",
8+
"default": true
9+
}
10+
}
11+
}
12+
]
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/** @file Unit tests for components/ContinuousScrollToggle.tsx. */
2+
/// <reference types="jest" />
3+
/// <reference types="@testing-library/jest-dom" />
4+
5+
import { render, screen } from '@testing-library/react';
6+
import userEvent from '@testing-library/user-event';
7+
import ContinuousScrollToggle from '../../components/ContinuousScrollToggle';
8+
9+
describe('ContinuousScrollToggle', () => {
10+
it('renders with a label', async () => {
11+
render(
12+
<ContinuousScrollToggle checked label="Continuous Scroll" onCheckedChange={jest.fn()} />,
13+
);
14+
const checkbox = screen.getByRole('checkbox');
15+
const label = screen.getByText('Continuous Scroll');
16+
17+
expect(label).toBeInTheDocument();
18+
expect(label).toHaveAttribute('for', checkbox.id);
19+
});
20+
21+
it('calls onCheckedChange when toggled', async () => {
22+
const onCheckedChange = jest.fn();
23+
render(<ContinuousScrollToggle checked onCheckedChange={onCheckedChange} />);
24+
const checkbox = screen.getByRole('checkbox');
25+
26+
expect(checkbox).toBeChecked();
27+
await userEvent.click(checkbox);
28+
29+
expect(onCheckedChange).toHaveBeenCalledWith(false);
30+
});
31+
});

0 commit comments

Comments
 (0)