Skip to content

Commit 171afdc

Browse files
alex-rawlings-yycimnasnainaecclaude
authored
Link tokens (#91)
* Add UI for linking phrases together * Adjustments to line styles * Add link buttons and improve styling (TESTS NOT UPDATED YET) * Rework focusRef, update tests * Symmetrize token ref focus * Hoist out phrase strip parts, improve split button handling * Add useArcPaths hook * Improve split border colour clarity * Add useArcSplitHandler hook * Update/add tests * Removed `--omit=optional` from Install extension dependencies step from lint git workflow (it was causing a failure) * Refactor phrase lookup to use id-keyed map for O(1) access Replace the token-ref-keyed linear search (`[...map.values()].find(l => l.analysisId === id)`) with a new `selectPhraseLinkByAnalysisId` selector and `usePhraseLinkByIdMap` hook, giving O(1) phrase lookup by id in `ArcOverlay`, `useArcSplitHandler`, and `SegmentView`. Also: - Move the phrase-revert effect from `PhraseBox` up to `InterlinearizerInner` so it fires even when all tokens are removed from the phrase - Fix `TokenChip` state sync to use `useEffect` instead of inline mutation during render - Fix `useArcPaths` dep array to use a version counter instead of a spread to satisfy the rules of hooks - Reset `phraseMode` on project switch in `InterlinearizerLoader` - Use a stable empty map constant in `PhraseBox` to avoid breaking memo - Improve arc key to include `phraseId` and `splitAfterTokenRef` * Add clarifying comment about `--omit-optional` omission * Minor adjustments, test coverage improvements * Minor improvements * Improve handling of inter-row arcs, other arc-related bugs and nits * Consolidate duplicated code * Add usePhraseHoverState test suite * Add PhraseStripContext * Add PhraseStrip component and bundle props * Set static control pill location relative to phrase box, clean up comments, consolidate tw classes * Add regions * Add tokenDocOrder prop, fix Set mutation, correct test assertions, extend makePhraseLink fixture, add JSDoc and region markers - Lift tokenDocOrder computation out of SegmentView into callers; add prop to SegmentView and SegmentView tests - Clone incoming Set in handleSplitHoverChange (usePhraseHoverState) so React sees a new reference on every update - Fix two ArcOverlay test assertions that used invalid two-argument not.toHaveBeenCalledWith on a single-argument handler; replace with not.toHaveBeenCalled() - Extend makePhraseLink with an optional surfaceTexts parameter so tests can supply TokenSnapshot.surfaceText values independently of tokenRef - Add JSDoc blocks for handleSplitHoverEnter and handleSplitHoverLeave in ArcOverlay - Update useArcPaths @returns JSDoc to describe ArcPathsResult including requiredRowGapPx - Correct PhraseBox JSDoc: one token remaining (not two) triggers phrase deletion; add region markers to ArcOverlay, PhraseBox, usePhraseHoverState, useArcPaths * Delete empty PhraseAnalysis automatically, tokenDocOrder only considers words, memoize PhraseGroup * Eliminate unnecessary abstraction, simplify computeAllArcPaths * Move edit/unlink controls to new confirm bar, fix edit mode bug, re-derive phrase surface text from new tokens * Fix SegmentView split button not working, improve gap calculation, clean up comments * Prevent 1-token phrases being created from edit mode * Minor adjustments * Rework arc drawing and related things * Cleanup * Minor adjustments * Minor adjustments * Hardenings for #91 (#93) * Harden ContinuousView scroll effect isInternal detection Replace the heuristic with an explicit lastDisplayUpdateWasInternalRef flag set at decision time in the focusedTokenRef effect. The scroll effect now reads only refs, removing the stale closure reads and the eslint-disable comment. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Add updatePhrase and setPhraseMode to revert effect deps Both are referentially stable (memoized dispatch and React state setter), so adding them costs nothing at runtime but removes the implicit reliance on that stability guarantee. Update the eslint-disable comment to explain why phraseMode itself remains intentionally omitted. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Document groupRef closure churn and its safe ref-cycling behavior Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> * Do minor phrase-arc cleanup (#95) * Do minor phrase-arc cleanup * Complete JSDocs * Refactor describeBoxPair into two locally specific function (#96) * Refactor describeBoxPair into two locally specific function * Fix mis-match * Fix onFocusPhrase breaking PhraseBox memoization * Improve visibility in light mode * Add toggles for phrase controls and options dropdown, subdivide components folder, add tooltip for disabled links * Fix punctuation rendering issues * Make SegmentView background clickable, shore up test coverage * Reposition options dropdown on resize * Minor adjustments * Minor adjustments * Improve AGENTS.md * Rename window* in ContinuousView to renderWindow*, improve render window in ContinuousView, improve handling of settings in InterlinearizerLoader, add dedicated mergePhrases reducer to analysisSlice, emit data-last-token-read on all render paths * Standardize spelling * Add REVIEW.md * Suggested cleanup on #91 (#99) * Merge mostly redundant tests * Update settings for VSCode to match our stylelint use * Add JSDocs * Fix pump() overwriting observerCallback via stub constructor new ResizeObserver(() => {}) inside pump() was invoking the stub constructor, replacing the stored observerCallback with a no-op on every call after the first. Replace with a pre-declared stubObserver plain object so pump() never touches the constructor again. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Sort cspell words * Fix brit spelling now covered in AGENTS.md --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> * Fix arc misalignment issue when out-of-segment links hidden * Add animation to make things smoother when out-of-segment links are hidden * Fix issue with inputs not focusing their token, add animation to SegmentView * Minor adjustment * Minor adjustments * Fix arc alignment, punctuation routing, and link-button polish; extract test helpers and reorganize types (#100) * Reserve link-slot space when hidden to prevent arc re-alignment Inactive link slots now use visibility:hidden instead of max-width collapse, so toggling hideInactiveLinkButtons no longer shifts phrase box positions. Removes the slotAnimationTick rAF loop and the hideInactiveLinkButtons re-center effect that compensated for the old layout shift. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Fix punctuation jumping when link icon is hidden link-slot was flex-col, stacking the icon wrapper above the punctuation. Changing to flex-row keeps them side-by-side so punctuation position no longer depends on the icon wrapper's height. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Fix in-phrase punctuation duplicating on every focus change buildRenderUnits was pushing into the shared TokenGroup.punctuationBetween arrays, which are owned by memoized objects that outlive a single render. Replace push() with assignment so each call resets the gap array instead of accumulating. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Fix crash on punctuation after the last token of a phrase group After the gapIndex fix, pendingIntraGroup pointed to a non-existent gap when the current token was the last in its group, causing a push() onto undefined when post-phrase punctuation arrived. Guard the assignment so the last token clears pendingIntraGroup instead; punctuation then falls into the inter-group LinkSlot as intended. Adds a regression test. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Cut 'yet' * Tune link button and arc contrast Link buttons: use foreground/60 (active) and foreground/20 (inactive) instead of muted-foreground at 100%/50%, widening the visual gap between actionable and suppressed slots. Arcs: reduce focused-phrase stroke opacity from 1.0 to 0.75 so the current phrase's arcs are less dominant relative to other phrases. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Fix punctuation layout and reduce arc contrast gap Punctuation layout: revert link-slot to flex-col so punctuation sits below the icon. Remove visibility:hidden from the icon wrapper and use opacity:0 instead; add display:inline-flex + min-height to ensure the wrapper always reserves the same vertical space even when TokenLinkIcon returns null. Arc contrast: reduce focused-phrase stroke opacity 0.75→0.60 and raise dimmed-phrase stroke opacity 0.8→1.0 (border is already low-contrast), narrowing the visual gap between the two states. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Guard mergePhrases reducer against targetPhraseId === absorbedPhraseId Without the guard the update succeeds but the subsequent delete removes the phrase that was just updated, leaving orphaned token references. Invariant was previously enforced only by callers. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Move controls/modals tests into matching subdirectories Aligns __tests__/components/controls/ and __tests__/components/modals/ with src/components/controls/ and src/components/modals/. Updates relative import paths accordingly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Disable pointer events and hide from a11y tree when link icon is suppressed opacity:0 alone left the invisible TokenLinkIcon hittable and focusable. Add pointerEvents:'none' and aria-hidden when suppressLinkIcon is true. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Import defaultScrRef from test-helpers instead of redefining it Two test files redeclared the same constant that test-helpers.ts already exports. Remove the duplicates and import the canonical export. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Extract makeWordToken fixture factory into test-helpers The same minimal word-token shape was defined six times across three test files under three different local names (mkWord, mkToken, mk). A single exported factory with a stable API replaces all six. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Extract emptyAnalysis factory into src/types/emptyFactories.ts Consolidates six independently constructed all-empty TextAnalysis objects across two source files and four test files into a single shared factory. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Reorganize types: rename to kebab-case, add @file headers, move token-layout types - emptyFactories.ts → empty-factories.ts, typeGuards.ts → type-guards.ts - Extract FocusContext/SlotFocusInfo/TokenGroup/LinkSlot/RenderUnit from utils/token-layout.ts into types/token-layout.ts - Add @file JSDoc to all three type files - Update all import sites (20 files) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Unexport ArcStrokeProps — no consumers outside phrase-arc.ts Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test: extract makeStubProject and reuse project fixtures * Fix idempotent punctuation routing in buildRenderUnits * Update comments * Make common withAnalysisStore test-helper * Extract in-file project setting helpers --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> * Minor adjustments * bugfix and cleanup: opacity hide, doc cleanup, helper functions (#101) Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> * Fix test failure --------- Co-authored-by: D. Ror. <imnasnainaec@gmail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 713e095 commit 171afdc

82 files changed

Lines changed: 14249 additions & 2449 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/lint.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,9 @@ jobs:
4040

4141
- name: Install extension dependencies
4242
working-directory: extension-repo
43-
run: npm ci --ignore-scripts --omit=optional
43+
# Cannot --omit=optional: @swc/core and lightningcss ship native binaries as optional deps
44+
# required by the build toolchain (SWC for transpilation, lightningcss for Tailwind CSS).
45+
run: npm ci --ignore-scripts
4446

4547
- name: Install core dependencies
4648
working-directory: paranext-core

.vscode/settings.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
{
22
"css.customData": [".vscode/tailwindcss.json"],
3+
"css.validate": false,
34

45
"editor.defaultFormatter": "esbenp.prettier-vscode",
56
"editor.formatOnSave": true,
67
"editor.rulers": [100],
78
"editor.wordWrapColumn": 100,
89

910
"eslint.validate": ["html", "javascript", "javascriptreact", "typescript", "typescriptreact"],
11+
"stylelint.validate": ["css", "less", "postcss", "scss", "tailwindcss"],
12+
"tailwindCSS.validate": false,
1013

1114
"files.associations": {
1215
"*.css": "tailwindcss",

AGENTS.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# AGENTS.md
22

3-
This file provides guidance to AI agents when working with code in this repository.
3+
This file provides guidance to AI agents creating and editing code in this repository.
4+
5+
Agents **reviewing** code should also read [REVIEW.md](REVIEW.md), which documents existing conventions that commonly trigger false-positive findings.
46

57
## Commands
68

@@ -143,7 +145,15 @@ Every function and method — exported or internal — must have a JSDoc block w
143145
- `@returns` describing the return value (omit only for `void`/`Promise<void>`).
144146
- `@throws` for every error condition the caller must handle; omit if the function never throws.
145147

146-
Type declarations (interfaces, type aliases, enums) must have a JSDoc summary on the type itself and on each field or member whose purpose is not self-evident from its name and type.
148+
Type declarations (interfaces, type aliases, enums) must have a JSDoc summary on the type itself and on each field or member whose purpose is not self-evident from its name and type. We document each field individually rather than describing the fields in the type-level summary.
149+
150+
## Spelling
151+
152+
Use American English throughout — in code, comments, JSDoc, and documentation:
153+
154+
- `center` not `centre`, `color` not `colour`, `behavior` not `behaviour`
155+
- `canceled`/`canceling` not `cancelled`/`cancelling`, `leveled`/`leveling` not `levelled`/`levelling`
156+
- `neighboring` not `neighbouring`, `favor` not `favour`, `signaled` not `signalled`
147157

148158
## UX decisions
149159

REVIEW.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# REVIEW.md
2+
3+
This file provides guidance to AI agents **reviewing** code in this repository. It documents existing conventions that commonly trigger false-positive findings, so reviewers don't flag intentional, already-handled patterns as issues.
4+
5+
Agents creating or editing code should follow [AGENTS.md](AGENTS.md); this file is supplementary and review-specific.
6+
7+
## Tailwind v4 at-rules
8+
9+
Tailwind v4 at-rules (`@utility`, `@apply`, `@theme`, `@config`, `@custom-variant`, `@layer`, `@source`, `@plugin`, etc.) are **already whitelisted** in [.stylelintrc.js](.stylelintrc.js)'s `scss/at-rule-no-unknown` `ignoreAtRules` list. Do **not** flag these as Stylelint violations, and do not suggest adding them to the config or adding `stylelint-disable` comments — they already pass. If you believe a lint rule is firing, run `npm run lint` and cite the actual output rather than inferring it from the rule name.
10+
11+
## Documentation completeness
12+
13+
Type declarations document each field individually rather than describing the fields in the type-level summary. When each field already carries its own JSDoc comment, the documentation is **complete** — do not flag it as inadequate, and do not ask for per-field details to be repeated or summarized in the type-level doc. The type-level summary describes the type as a whole; the per-field comments describe the fields. Only flag a field that is genuinely missing its own comment.
14+
15+
Before reporting any documentation as missing, open the file and confirm the JSDoc is actually absent. Do not infer missing docs from a symbol name, a type signature, or an excerpt — read the declaration.
16+
17+
## Keyboard navigation
18+
19+
Keyboard accessibility is planned but not yet implemented. Do not flag missing `tabIndex` attributes, absent `aria-*` roles, or gaps in focus management as issues — these will be addressed in a dedicated pass once the core interaction model is stable.
20+
21+
## Mock cleanup in tests
22+
23+
[jest.config.ts](jest.config.ts) sets both `resetMocks: true` and `restoreMocks: true`. This means every `jest.spyOn(...)` is automatically restored to its original implementation after each test — tests do **not** need a manual `mockRestore()` or `jest.restoreAllMocks()` in `afterEach` for spies. Do not flag spies as leaking or suggest adding cleanup for them.
24+
25+
Manual cleanup in `afterEach` is only required for state that `restoreMocks` cannot undo, such as plain reassignment of a global (e.g. `global.ResizeObserver = ...`). When you see an `afterEach` restoring only some things, confirm whether the rest are spies (auto-restored) before flagging an omission.

__mocks__/lucide-react.tsx

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,43 @@ export function Info(props: Readonly<{ size?: number; className?: string }>): Re
3434
export function Trash2(props: Readonly<{ size?: number; className?: string }>): ReactElement {
3535
return <svg data-testid="trash2-icon" {...props} />;
3636
}
37+
38+
/**
39+
* Stub for the X icon.
40+
*
41+
* @param props - SVG props forwarded from the component.
42+
* @returns A ReactElement SVG element used as an X icon stub in tests.
43+
*/
44+
export function X(props: Readonly<{ size?: number; className?: string }>): ReactElement {
45+
return <svg data-testid="x-icon" {...props} />;
46+
}
47+
48+
/**
49+
* Stub for the Link2 (link) icon used by the between-token link button.
50+
*
51+
* @param props - SVG props forwarded from the component.
52+
* @returns A ReactElement SVG element used as a link icon stub in tests.
53+
*/
54+
export function Link2(props: Readonly<{ size?: number; className?: string }>): ReactElement {
55+
return <svg data-testid="link2-icon" {...props} />;
56+
}
57+
58+
/**
59+
* Stub for the Link2Off (unlink) icon used by the between-token unlink and arc-split buttons.
60+
*
61+
* @param props - SVG props forwarded from the component.
62+
* @returns A ReactElement SVG element used as an unlink icon stub in tests.
63+
*/
64+
export function Link2Off(props: Readonly<{ size?: number; className?: string }>): ReactElement {
65+
return <svg data-testid="link2off-icon" {...props} />;
66+
}
67+
68+
/**
69+
* Stub for the Settings gear icon used by the view-options dropdown button.
70+
*
71+
* @param props - SVG props forwarded from the component.
72+
* @returns A ReactElement SVG element used as a settings icon stub in tests.
73+
*/
74+
export function Settings(props: Readonly<{ size?: number; className?: string }>): ReactElement {
75+
return <svg data-testid="settings-icon" {...props} />;
76+
}

__mocks__/papi-frontend-react.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
/**
77
* Known data-provider method names exposed by this mock. Tests that call an unlisted method will
88
* receive a descriptive error rather than silently returning `undefined`, which mirrors the real
9-
* PAPI behaviour where requesting an unsupported provider key is a programmer error.
9+
* PAPI behavior where requesting an unsupported provider key is a programmer error.
1010
*/
1111
const KNOWN_PROJECT_DATA_METHODS = new Set(['BookUSJ']);
1212

__mocks__/platform-bible-react.tsx

Lines changed: 45 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* without extra transform configuration. This stub provides the subset used by the extension.
44
*/
55

6+
import { forwardRef } from 'react';
67
import type { ReactElement, ReactNode } from 'react';
78

89
export interface MenuItemContainingCommand {
@@ -188,8 +189,8 @@ export function ScrollGroupSelector({
188189

189190
/**
190191
* Stub button that passes through `children`, `onClick`, `type`, `className`, `disabled`,
191-
* `aria-label`, and forwards them to a native `<button>` element; `variant` and `size` are
192-
* accepted but ignored.
192+
* `aria-label`, `aria-expanded`, `aria-haspopup`, `data-testid`, and `ref` to a native `<button>`
193+
* element; `variant` and `size` are accepted but ignored.
193194
*
194195
* @param props - Component props.
195196
* @param props.children - Button content.
@@ -199,39 +200,60 @@ export function ScrollGroupSelector({
199200
* @param props.disabled - Whether the button is disabled.
200201
* @param props.variant - Ignored styling variant.
201202
* @param props.size - Ignored size variant.
202-
* @returns A native `<button>` element with `aria-label` forwarded.
203+
* @param props['aria-label'] - Accessible label.
204+
* @param props['aria-expanded'] - Expanded state for popup triggers.
205+
* @param props['aria-haspopup'] - Haspopup attribute.
206+
* @param props['data-testid'] - Test identifier.
207+
* @param ref - Forwarded ref to the underlying button element.
208+
* @returns A native `<button>` element with standard attributes forwarded.
203209
*/
204-
export function Button({
205-
children,
206-
onClick,
207-
type,
208-
className,
209-
disabled,
210-
variant: _variant,
211-
size: _size,
212-
'aria-label': ariaLabel,
213-
}: Readonly<{
214-
children?: ReactNode;
215-
onClick?: () => void;
216-
type?: 'button' | 'submit' | 'reset';
217-
className?: string;
218-
disabled?: boolean;
219-
variant?: 'default' | 'secondary' | 'destructive' | 'ghost' | 'outline' | 'link';
220-
size?: 'default' | 'sm' | 'lg' | 'icon';
221-
'aria-label'?: string;
222-
}>): ReactElement {
210+
export const Button = forwardRef<
211+
HTMLButtonElement,
212+
Readonly<{
213+
children?: ReactNode;
214+
onClick?: () => void;
215+
type?: 'button' | 'submit' | 'reset';
216+
className?: string;
217+
disabled?: boolean;
218+
variant?: 'default' | 'secondary' | 'destructive' | 'ghost' | 'outline' | 'link';
219+
size?: 'default' | 'sm' | 'lg' | 'icon';
220+
'aria-label'?: string;
221+
'aria-expanded'?: boolean;
222+
'aria-haspopup'?: boolean | 'true' | 'false' | 'menu' | 'listbox' | 'tree' | 'grid' | 'dialog';
223+
'data-testid'?: string;
224+
}>
225+
>(function ButtonImpl(
226+
{
227+
children,
228+
onClick,
229+
type,
230+
className,
231+
disabled,
232+
variant: _variant,
233+
size: _size,
234+
'aria-label': ariaLabel,
235+
'aria-expanded': ariaExpanded,
236+
'aria-haspopup': ariaHaspopup,
237+
'data-testid': testId,
238+
},
239+
ref,
240+
) {
223241
return (
224242
<button
243+
ref={ref}
225244
type={type ?? 'button'}
226245
onClick={onClick}
227246
className={className}
228247
aria-label={ariaLabel}
248+
aria-expanded={ariaExpanded}
249+
aria-haspopup={ariaHaspopup}
250+
data-testid={testId}
229251
disabled={disabled}
230252
>
231253
{children}
232254
</button>
233255
);
234-
}
256+
});
235257

236258
/**
237259
* Stub book/chapter control that displays the current reference as text and exposes a single

contributions/localizedStrings.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,14 @@
1414
"%interlinearizer_projectSettings_title%": "Interlinearizer",
1515
"%interlinearizer_projectSettings_continuousScroll%": "Continuous Scroll",
1616
"%interlinearizer_projectSettings_continuousScrollDescription%": "Display tokens in a continuous horizontal scroll strip instead of chapter-segmented rows",
17-
"%interlinearizer_continuousScrollToggle%": "Continuous Scroll",
17+
"%interlinearizer_viewOption_continuousScroll%": "Continuous Scroll",
18+
"%interlinearizer_viewOption_hideInactiveLinkButtons%": "Hide out-of-segment link buttons",
19+
"%interlinearizer_viewOption_simplifyPhrases%": "Show phrase controls on focus only",
20+
"%interlinearizer_projectSettings_hideInactiveLinkButtons%": "Hide Out-of-Segment Link Buttons",
21+
"%interlinearizer_projectSettings_hideInactiveLinkButtonsDescription%": "Hide link buttons between phrases in segments that are not currently active",
22+
"%interlinearizer_projectSettings_simplifyPhrases%": "Show Phrase Controls on Focus Only",
23+
"%interlinearizer_projectSettings_simplifyPhrasesDescription%": "Hide interactive controls (split, unlink, remove-token) on phrases that are not currently focused, leaving only their style change on hover",
24+
"%interlinearizer_linkButton_crossSegmentDisabledTooltip%": "Cross-segment phrases are not supported. This link button is outside the current segment.",
1825

1926
"%interlinearizer_modal_create_title%": "Create Interlinear Project",
2027
"%interlinearizer_modal_create_name_label%": "Name (optional)",

contributions/projectSettings.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,16 @@
66
"label": "%interlinearizer_projectSettings_continuousScroll%",
77
"description": "%interlinearizer_projectSettings_continuousScrollDescription%",
88
"default": true
9+
},
10+
"interlinearizer.hideInactiveLinkButtons": {
11+
"label": "%interlinearizer_projectSettings_hideInactiveLinkButtons%",
12+
"description": "%interlinearizer_projectSettings_hideInactiveLinkButtonsDescription%",
13+
"default": false
14+
},
15+
"interlinearizer.simplifyPhrases": {
16+
"label": "%interlinearizer_projectSettings_simplifyPhrases%",
17+
"description": "%interlinearizer_projectSettings_simplifyPhrasesDescription%",
18+
"default": false
919
}
1020
}
1121
}

cspell.json

Lines changed: 22 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -13,57 +13,48 @@
1313
"dictionaryDefinitions": [],
1414
"dictionaries": [],
1515
"words": [
16+
"affordances",
1617
"appdata",
17-
"asyncs",
18-
"autodocs",
18+
"bara",
1919
"BBCCCVVV",
20-
"Discontiguous",
21-
"dockbox",
20+
"deconflict",
21+
"deconfliction",
22+
"deconflicts",
23+
"discontig",
24+
"discontiguous",
2225
"eflomal",
23-
"electronmon",
26+
"elohim",
2427
"endregion",
2528
"eten",
26-
"finalizer",
27-
"Fragmenter",
28-
"guids",
29-
"hopkinson",
29+
"fontsource",
30+
"hoverable",
3031
"iframes",
3132
"imte",
3233
"interlinearization",
3334
"interlinearize",
3435
"interlinearizer",
35-
"interlinearizing",
36+
"labelable",
3637
"lightningcss",
37-
"localstorage",
38-
"maximizable",
3938
"morphosyntactic",
40-
"networkable",
41-
"Newtonsoft",
42-
"nodebuffer",
4339
"nums",
40+
"okina",
4441
"papi",
45-
"papis",
4642
"paranext",
4743
"paratext",
4844
"pdpf",
49-
"pdps",
5045
"plusplus",
51-
"proxied",
52-
"Punct",
53-
"recalc",
54-
"reinitializing",
55-
"reserialized",
46+
"punct",
47+
"relayout",
5648
"sandboxed",
5749
"scriptio",
50+
"scrollers",
51+
"shadcn",
5852
"sillsdev",
59-
"steenwyk",
60-
"stringifiable",
61-
"Struc",
53+
"struc",
6254
"Stylesheet",
6355
"typedefs",
64-
"unanalyzed",
65-
"unregistering",
66-
"unregisters",
56+
"unhover",
57+
"unphrased",
6758
"unreviewed",
6859
"unsub",
6960
"unsubs",
@@ -72,8 +63,9 @@
7263
"usfm",
7364
"verseref",
7465
"versification",
75-
"Wordform"
66+
"wordform",
67+
"ZWNJ"
7668
],
77-
"ignoreWords": [],
69+
"ignoreWords": ["Ελληνικά", "homme", "ʼelohim", "ʻokina"],
7870
"import": []
7971
}

0 commit comments

Comments
 (0)