Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
4297c2f
feat(Verse): add verse selection functionality
cameronapak Jan 27, 2026
9c7c7d0
feat(config): set default bible version to bsb
cameronapak Jan 27, 2026
bb96a59
refactor(verse): Refactor Verse component to use BibleTextHtml
cameronapak Feb 2, 2026
6c80460
fix(ui): preserve verse selection when toggling footnotes
cameronapak Jan 27, 2026
1a7e6b9
feat(ui): add verse highlighting support to BibleTextView
cameronapak Feb 2, 2026
3a4fa5b
fix(ui): revert default Bible version
cameronapak Jan 28, 2026
a19057a
fix(ui): add missing html dependency to verse selection/highlight effect
cameronapak Jan 29, 2026
6aa5dc1
fix(ui): only show pointer cursor when verses are selectable
cameronapak Jan 29, 2026
4447b99
fix(ui): use ref to avoid stale closure in verse selection handler
cameronapak Jan 29, 2026
bb1e5f0
fix(ui): pre-optimize Vite deps and quiet MSW logs for CI stability
cameronapak Jan 29, 2026
3658c6c
chore(storybook): remove optimizeDeps configuration
cameronapak Jan 29, 2026
6d6b49f
docs: added changeset
cameronapak Jan 29, 2026
673e454
feat: Add BoxStackIcon component
cameronapak Jan 30, 2026
354a984
feat: Add BoxArrowUpIcon component
cameronapak Jan 30, 2026
5ca255b
feat(ui): wire up VerseActionPopover with BibleTextView
cameronapak Jan 30, 2026
42ba15b
Fix: Conditionally render VerseActionPopover
cameronapak Feb 2, 2026
5216edc
Fix: Prevent rendering popover when closed
cameronapak Feb 2, 2026
f959027
Refactor: Refactor verse action popover highlight logic
cameronapak Feb 2, 2026
d1f6019
fix: clicking X clears all highlights from selected verses
cameronapak Feb 2, 2026
7a3d2ad
fix: allow re-highlighting verses with different color
cameronapak Feb 2, 2026
f4c6143
feat: show active highlight colors first in popover
cameronapak Feb 2, 2026
52da340
fix: don't show duplicate color when verse already has that highlight
cameronapak Feb 2, 2026
79ec413
fix: show all apply colors when selection has unhighlighted verses
cameronapak Feb 2, 2026
8542987
fix: always show all 5 apply colors in popover
cameronapak Feb 2, 2026
33eea9d
Docs: Add Verse Action Popover PRD
cameronapak Feb 2, 2026
087a210
Feature: Add VerseActionPopover component
cameronapak Feb 2, 2026
5f477ac
test: Add tests for VerseActionPopover
cameronapak Feb 2, 2026
fee7cda
fix(verse-action-popover): only show apply buttons for inactive
cameronapak Feb 2, 2026
68d5bbe
Docs: Refactor action popover acceptance criteria
cameronapak Feb 2, 2026
e6b5005
Refactor: Update verse action popover logic
cameronapak Feb 2, 2026
1eb99fd
Feat: Add edge-case AC for removing highlight
cameronapak Feb 2, 2026
b45e408
Docs: Add PRD and task for verse action popover
cameronapak Feb 2, 2026
1f5ae71
refactor: Refactor verse action popover for per-color clearing
cameronapak Feb 2, 2026
f98be90
fix(verse-action-popover): resolve TS errors and improve accessibility
cameronapak Feb 2, 2026
462ed34
Fix: Improve highlight button accessibility label
cameronapak Feb 2, 2026
022a7f6
Fix: Update highlight button label in tests
cameronapak Feb 2, 2026
98ca16b
style(ui): remove unnecessary comments
cameronapak Feb 2, 2026
4fffc78
Fix: Remove AC 10 from PRD-verse-action-popover
cameronapak Feb 2, 2026
4c853f9
Docs: rm already existing changeset
cameronapak Feb 2, 2026
4e91312
Refactor bible reader styles
cameronapak Feb 2, 2026
40f4af9
Remove PRD and task docs for verse action popover
cameronapak Feb 2, 2026
1f2f1fa
Remove verse action popover PRD
cameronapak Feb 2, 2026
e1b0b30
feat(ui): Implement SSR safety and anchor positioning
cameronapak Feb 2, 2026
22a5448
Add caret to verse action popover
cameronapak Feb 4, 2026
b30c8f6
Adjust verse action popover translate offset
cameronapak Feb 4, 2026
b1ab372
use the box shadow that was given in the designs.
cameronapak Feb 4, 2026
fb5d6c8
Refactor verse action popover to Radix UI
cameronapak Feb 4, 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
23 changes: 23 additions & 0 deletions packages/ui/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,14 @@ src/index.ts # Entry point with style injection side effect
✅ Do: Use Radix UI primitives from `components/ui/` for low-level behaviors (modals, popovers, etc.)
✅ Do: Use Tailwind classes with the `yv:` prefix only
✅ Do: Use semantic theme tokens (`yv:text-muted-foreground`, `yv:bg-destructive`) instead of arbitrary colors
✅ Do: Keep components SSR-safe (see SSR SAFETY section below)

❌ Don't: Make raw network requests from UI components
❌ Don't: Import from `@youversion/platform-core` directly (except re-exports in index.ts)
❌ Don't: Add global CSS files; all styling goes through Tailwind build and `injectStyles`
❌ Don't: Use unprefixed Tailwind classes (causes collisions in consumer apps)
❌ Don't: Access `window`, `document`, or browser APIs outside of `useEffect`
❌ Don't: Use `useLayoutEffect` (causes React warnings during SSR)

## CONVENTIONS
- React 19+ peer dependency
Expand Down Expand Up @@ -167,6 +170,26 @@ From repo root, `pnpm build` runs Turbo which builds in order:
2. `@youversion/platform-react-hooks`
3. `@youversion/platform-react-ui` (build:css → build:js → build:types)

## SSR SAFETY
Components must work with SSR frameworks (Next.js, Remix, etc.) without errors or warnings:

- **All browser API access must be inside `useEffect`** - never access `window`, `document`, `navigator`, `localStorage`, or DOM APIs at module level or during render
- **Use `useEffect` instead of `useLayoutEffect`** - `useLayoutEffect` logs warnings during SSR; since our components typically start hidden/closed, the visual flash concern doesn't apply
- **Guard dynamic imports** - polyfills and browser-only code should be loaded inside `useEffect`
- **Props like `anchorElement` will be `null` during SSR** - always check before accessing

Example pattern for browser-only code:
```tsx
useEffect(() => {
// Safe: only runs on client after hydration
if ('anchorName' in document.documentElement.style) {
// native support
} else {
// load polyfill
}
}, []);
```

## CRITICAL
- **Side effect**: importing package injects styles automatically
- Never skip build:css step (styles required for __YV_STYLES__ constant)
Expand Down
1 change: 1 addition & 0 deletions packages/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"test:integration": "vitest run"
},
"dependencies": {
"@oddbird/css-anchor-positioning": "^0.8.0",
"@radix-ui/react-accordion": "1.2.12",
"@radix-ui/react-dialog": "1.1.15",
"@radix-ui/react-popover": "1.1.15",
Expand Down
23 changes: 23 additions & 0 deletions packages/ui/src/components/icons/box-arrow-up.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import type { ComponentProps, ReactElement } from 'react';

export function BoxArrowUpIcon(props: ComponentProps<'svg'>): ReactElement {
return (
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M16.1213 9.18728C15.7307 9.57781 15.0976 9.57781 14.707 9.18728L13 7.48023V15C13 15.5523 12.5523 16 12 16C11.4477 16 11 15.5523 11 15V7.34819L9.12126 9.22693C8.73074 9.61746 8.09757 9.61746 7.70705 9.22693C7.31652 8.83641 7.31652 8.20324 7.70705 7.81272L11.2269 4.29289C11.6174 3.90237 12.2506 3.90237 12.6411 4.29289L16.1213 7.77307C16.5118 8.16359 16.5118 8.79676 16.1213 9.18728Z"
fill="currentColor"
/>
<path
d="M6 12C5.44772 12 5 12.4478 5 13V18C5 19.1046 5.89543 20 7 20H17C18.1046 20 19 19.1046 19 18V13C19 12.4478 18.5523 12 18 12C17.4477 12 17 12.4478 17 13V17.5C17 17.7762 16.7761 18 16.5 18H7.5C7.22386 18 7 17.7762 7 17.5V13C7 12.4478 6.55228 12 6 12Z"
fill="currentColor"
/>
</svg>
);
}
25 changes: 25 additions & 0 deletions packages/ui/src/components/icons/box-stack.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import type { ComponentProps, ReactElement } from 'react';

export function BoxStackIcon(props: ComponentProps<'svg'>): ReactElement {
return (
<svg
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M13.3333 3.77605H10.8333C9.60697 3.77605 8.85748 3.77965 8.3157 3.85249C8.06468 3.88624 7.92738 3.92742 7.85389 3.95766C7.79391 3.98233 7.77524 3.99975 7.76249 4.0125C7.74974 4.02525 7.73232 4.04392 7.70765 4.1039C7.67741 4.17739 7.63623 4.31469 7.60248 4.56571C7.52964 5.10749 7.52604 5.85698 7.52604 7.08334V9.58334C7.52604 10.8097 7.52964 11.5592 7.60248 12.101C7.63623 12.352 7.67741 12.4893 7.70765 12.5628C7.73232 12.6228 7.74974 12.6414 7.76249 12.6542C7.77524 12.6669 7.79391 12.6844 7.85389 12.709C7.92738 12.7393 8.06468 12.7805 8.3157 12.8142C8.85748 12.887 9.60697 12.8906 10.8333 12.8906H13.3333C14.5597 12.8906 15.3092 12.887 15.851 12.8142C16.102 12.7805 16.2393 12.7393 16.3128 12.709C16.3728 12.6844 16.3914 12.6669 16.4042 12.6542C16.4169 12.6414 16.4343 12.6228 16.459 12.5628C16.4893 12.4893 16.5304 12.352 16.5642 12.101C16.637 11.5592 16.6406 10.8097 16.6406 9.58334V7.08334C16.6406 5.85698 16.637 5.10749 16.5642 4.56571C16.5304 4.31469 16.4893 4.17739 16.459 4.1039C16.4343 4.04392 16.4169 4.02525 16.4042 4.0125C16.3914 3.99975 16.3728 3.98233 16.3128 3.95766C16.2393 3.92742 16.102 3.88624 15.851 3.85249C15.3092 3.77965 14.5597 3.77605 13.3333 3.77605ZM6.56557 2.81558C5.83333 3.54781 5.83333 4.72632 5.83333 7.08334V9.58334C5.83333 11.9404 5.83333 13.1189 6.56557 13.8511C7.2978 14.5833 8.47631 14.5833 10.8333 14.5833H13.3333C15.6904 14.5833 16.8689 14.5833 17.6011 13.8511C18.3333 13.1189 18.3333 11.9404 18.3333 9.58334V7.08334C18.3333 4.72632 18.3333 3.54781 17.6011 2.81558C16.8689 2.08334 15.6904 2.08334 13.3333 2.08334H10.8333C8.47631 2.08334 7.2978 2.08334 6.56557 2.81558Z"
fill="currentColor"
/>
<path
d="M4.16667 4.58334V12.9167C4.16667 14.7576 5.65905 16.25 7.5 16.25H15.8333C15.8333 17.0833 15.094 17.9167 14.1667 17.9167H7.5C4.73858 17.9167 2.5 15.6781 2.5 12.9167V6.25001C2.5 5.41668 3.33333 4.58334 4.16667 4.58334Z"
fill="currentColor"
/>
</svg>
);
}
16 changes: 16 additions & 0 deletions packages/ui/src/components/icons/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export { ArrowLeftIcon } from './arrow-left';
export { BookOpenIcon } from './book-open';
export { BoxArrowUpIcon } from './box-arrow-up';
export { BoxStackIcon } from './box-stack';
export { ChevronDownIcon } from './chevron-down';
export { Footnote, Footnote as FootnoteIcon } from './footnote';
export { GearIcon } from './gear';
export { GlobeIcon } from './globe';
export { InfoIcon } from './info';
export { LoaderIcon } from './loader';
export { PersonIcon } from './person';
export { SearchIcon } from './search';
export { Share, Share as ShareIcon } from './share';
export { Votd, Votd as VotdIcon } from './votd';
export { XIcon } from './x';
export { YouVersionLogo } from './youversion-logo';
1 change: 1 addition & 0 deletions packages/ui/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ export { YouVersionAuthButton, type YouVersionAuthButtonProps } from './YouVersi
export { VerseOfTheDay, type VerseOfTheDayProps } from './verse-of-the-day';
export { BibleTextView, type BibleTextViewProps } from './verse';
export { BibleWidgetView, type BibleWidgetViewProps } from './bible-widget-view';
export { VerseActionPopover, HIGHLIGHT_COLORS } from './verse-action-popover';
Loading