8139ff1282
Task #301. Fonts: - Extracted 22 curated font files from the user's uploaded zip into artifacts/tx-os/public/fonts/ (DIN Next LT Arabic ×5, Tajawal ×7, Helvetica Neue LT Arabic ×3, Helvetica Neue ×5, Majalla ×2). - New artifacts/tx-os/src/custom-fonts.css with @font-face blocks using font-display: swap; imported from index.css. - Replaced FONT_OPTIONS in editable-cell.tsx with the curated set; each <option> previews in its own font family. Attendee keyboard nav: - EditableCell: new onTabNext / onTabPrev props, captured into refs so the empty-deps useEditor always sees the latest callback. handleKeyDown now intercepts Tab and Shift+Tab (preventDefaults + saveEdit + dispatches the matching callback). - AttendeeFlow: - new chainStartAdd path that bypasses the hasAnyPending UI gate so Tab can chain a fresh pending row even while one is open (state-level guard in setPendingAttendee still prevents overlap). - new focusedAttendeeIdx state lets a sibling row request edit mode on a target row via startInEditMode + onStartedEditing. - findPrevPersonInSection walks back through items[] and stops at a subheading, so Shift+Tab never crosses a section boundary; no-op on the first row of a section (saveEdit still runs). - Existing person row passes onTabNext (chain new pending after i) and onTabPrev (focus prev person in same section). - Pending row passes the same pair using inlineGhostTargetListIdx ?? items.length as the start anchor. Non-attendee EditableCells (meeting title, merge title, subheadings) are unchanged — they pass no tab callbacks so default browser focus traversal still applies. Verified: TS clean, e2e covers forward Tab chain, Shift+Tab between existing rows, first-in-section no-op, and Shift+Tab from the pending row.
25 KiB
1280x720px
25 KiB
1280x720px