rtl-layout

GitHub

用于创建或修改 OpenChamber UI 的 RTL 布局,处理水平定位、偏移量、滚动计算及箭头键导航等。

.agents/skills/rtl-layout/SKILL.md openchamber/openchamber

Trigger Scenarios

创建或修改 RTL 界面布局 处理水平定位与偏移量 实现 RTL 滚动数学逻辑

Install

npx skills add openchamber/openchamber --skill rtl-layout -g -y
More Options

Non-standard path

npx skills add https://github.com/openchamber/openchamber/tree/main/.agents/skills/rtl-layout -g -y

Use without installing

npx skills use openchamber/openchamber@rtl-layout

指定 Agent (Claude Code)

npx skills add openchamber/openchamber --skill rtl-layout -a claude-code -g -y

安装 repo 全部 skill

npx skills add openchamber/openchamber --all -g -y

预览 repo 内 skill

npx skills add openchamber/openchamber --list

SKILL.md

Frontmatter
{
    "name": "rtl-layout",
    "description": "Use when creating or modifying OpenChamber UI layout, horizontal positioning, offsets or scroll math, resize or drag handles, arrow-key navigation, directional icons, or slide animations."
}

RTL Layout

Arabic and Hebrew mirror the whole interface. getLocaleDirection in packages/ui/src/lib/i18n/runtime.ts derives the direction from the UI locale; the i18n provider puts it on <html dir> and hands it to Base UI's DirectionProvider. Components read it as useI18n().direction, or as isRightToLeft(el) from @/lib/i18n in event handlers and code outside React. Do not call el.matches(':dir(rtl)'): it throws on WebKit before 16.4. Adding a right-to-left locale follows locale-ui-patterns and also puts it in RTL_LOCALES there.

Every layout change works in both directions. The test: English stays pixel-identical, and Arabic is its mirror image.

Logical by default

Write sides as start and end of the line: ms-/me-, ps-/pe-, inset-s-/inset-e-, text-start/text-end, rounded-s/rounded-e/rounded-ss, border-s/border-e; in CSS and inline styles margin-inline-start, padding-inline-start, inset-inline-start. Flex and grid already follow dir, so DOM order stays semantic.

What CSS cannot express flips with the rtl: variant: translate-x-* (data-[checked]:translate-x-4 rtl:data-[checked]:-translate-x-4), bg-gradient-to-r rtl:bg-gradient-to-l, origin-top-left rtl:origin-top-right, and inline transforms built from a sign. A fade toward the end of a line uses linear-gradient(var(--oc-to-inline-end), …).

Physical on purpose

Some sides belong to the screen, not the line. The lint rule openchamber/no-physical-sides (tools/oxlint/openchamber, enabled in oxlint.config.ts) flags physical classes in packages/ui class lists, so a deliberate one carries // oxlint-disable-next-line openchamber/no-physical-sides -- <why it is physical>:

  • OS window controls. macOS traffic lights stay top left in every language; frameless Windows/Linux controls stay on the side the user picked. The titlebar publishes --oc-titlebar-start-inset and maps controls through getInlineStartSide(direction) (see Header.tsx, TitlebarLeftControls.tsx).
  • Geometry from measurement. An element moved by offsetLeft, getBoundingClientRect().left or clientX anchors with left-0, because the numbers are physical (the active-tab pill in sortable-tabs-strip.tsx).
  • Content that reads left to right: code, diffs, terminal output and its key strip, file paths and path fields, URLs, IDs, charts along a time axis. The container gets dir="ltr", so its own logical classes resolve as physical inside it.
  • Keyboard keys and labels that name a physical key ("close tabs to the left" means the screen's left).

Direction-aware behaviour

  • Resize and drag. A handle on a panel's edge changes width by the pointer delta times a sign: (clientX - startX) * (rtl ? -1 : 1) for a start-side panel. Arrow keys on the handle take the same sign.
  • Horizontal scroll. In RTL scrollLeft is 0 at the start and negative toward the end. Distance from the start is Math.abs(scrollLeft); distance from the physical left is scrollWidth - clientWidth + scrollLeft. Wheel-to-horizontal mapping flips the delta.
  • Previous/next keys. ArrowLeft and ArrowRight swap meaning when they step through a horizontal sequence (tabs, image viewer, thinking levels).
  • Sorting. horizontalListSortingStrategy assumes later items sit further right; pass rectSortingStrategy in RTL (see drag-to-reorder).
  • Slide-ins. A drawer, pushed page or row swipe moves toward the side its trigger sits on; compute the offset sign from direction and mirror edge swipes with it (MobileApp.tsx, MobileSessionSwipe.tsx).

Mixed-direction text

User content (session titles, run names, file names in lists) gets dir="auto" so it shows its own start when truncated. Text whose direction differs from the UI aligns with the interface through oc-ui-start-align, so it lines up with the rows around it. Values made of numbers and units ("~41 tok/s", "6.6K ↑ · 242 ↓") also take dir="auto". Markdown already resolves direction per block; see components/chat/message/parts/DOCUMENTATION.md before touching it.

Icons

DIRECTIONAL_ICONS in components/icon/Icon.tsx lists the icons that mirror in RTL (back/forward, chevrons, panel sides, send); one CSS rule flips them through :dir(rtl), so an icon inside a dir="ltr" block stays as drawn. A new icon whose meaning points somewhere joins the set. The flip happens before the <svg>'s own rotation, so a chevron that turns a quarter turn pairs it: rotate-90 rtl:-rotate-90.

Verify

  1. Take English screenshots of the affected screens before the change and after it; they match pixel for pixel.
  2. Switch to Arabic (localStorage['openchamber.i18n.v1'] = '{"locale":"ar"}') and check the same screens, then drag, scroll and use the arrow keys on whatever changed.
  3. For phone layouts, check the drawer and swipe direction at a 390px touch viewport.

Version History

  • bf977d2 Current 2026-10-19 13:05

Same Skill Collection

.agents/skills/changelog-authoring/SKILL.md
.agents/skills/clack-cli-patterns/SKILL.md
.agents/skills/communication-style/SKILL.md
.agents/skills/desktop-shell/SKILL.md
.agents/skills/drag-to-reorder/SKILL.md
.agents/skills/enterprise-boundary/SKILL.md
.agents/skills/isolated-space-boundary/SKILL.md
.agents/skills/locale-ui-patterns/SKILL.md
.agents/skills/openchamber-change-discipline/SKILL.md
.agents/skills/opencode-v2/SKILL.md
.agents/skills/performance-engineering/SKILL.md
.agents/skills/pr-review/SKILL.md
.agents/skills/relay-transport/SKILL.md
.agents/skills/serve-sim/SKILL.md
.agents/skills/settings-ui-patterns/SKILL.md
.agents/skills/sync-state-invariants/SKILL.md
.agents/skills/theme-system/SKILL.md
.agents/skills/triage-issues/SKILL.md
.agents/skills/triage-prs/SKILL.md
.agents/skills/ui-api-decoupling/SKILL.md
.agents/skills/update-changelog/SKILL.md
.agents/skills/writing-for-agents/SKILL.md

Metadata

Files
0
Version
bf977d2
Hash
7ba4f5b2
Indexed
2026-10-19 13:05

Accueil - Wiki
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-10-31 21:38
浙ICP备14020137号-1