Skip to content
fandhe-frontendcore v0.4.3
GitHub

Image Cropper

矩形の切り抜き範囲(crop rect)を選択させる部品です。表示画像上に選択枠と方位別ハンドルを重ね、選択範囲の x/y/width/height を値として保持します。canvas による実際のピクセル切り出し(画像処理)は本部品のスコープ外で、利用者側の責務です。

fandhe-frontend-headless-ui の image_cropper mod が提供する構造・アクセシビリティ(WAI-ARIA・キーボード操作)・表示状態(data-*)のみを持つ unstyled 部品です。Themes 版が備える見た目は持たず、anatomy・ARIA・data-* のみを提供します。CSS は利用者が当てます。

参照実装(ark-ui/zag.js image-cropper machine)との突合により、キーボード操作の受け口は handle ではなく selection(focusable な role="slider"、aria-roledescription="2d slider")へ集約されています。handle は role="presentation" + aria-hidden="true"(非 focusable)で、data-position(旧 data-handle-position から改名)のみを出力します。ImageCropperProps { disabled, dragging } に応じて root/viewport/selection/handle へ data-disabled、root/selection/grid へ data-dragging を出力します。grid に GridAxis::Horizontal/Vertical を渡すと data-axis を出力します(省略時は単一コンテナ)。action_for_key(key, modifiers) はキーボード操作(Arrow = 移動、Alt+Arrow = SE ハンドル基準のリサイズ、Shift/Ctrl(Cmd) で step 拡大)の対応表を純粋関数として提供しますが、実際の DOM keydown 配線は fandhe-frontend-wasm-full 側の後続責務です。

スタイル済みの表示例は Image Cropper を参照してください。

関連 API: fandhe-frontend-headless-ui API

自前 CSS の最小例

Themes 版を使わず本部品を直接使う場合、[data-scope="image-cropper"][data-part="..."] セレクタでスタイルを当てます。以下は選択枠・ハンドル・selection のフォーカスリングの最小例です。headless 層は選択範囲の位置・寸法を CSS カスタムプロパティとして自動出力しないため、呼び出し側が ImageCropper::x_percent() 等から selection の attrs へ ("style", "--crop-x: 20%; ...") のように現在値を渡す必要があります(fandhe-frontend-pre-styled-ui の selection はこれを内部で一元的に組み立てます)。

CSS
[data-scope="image-cropper"][data-part="selection"] {
  position: absolute;
  /* --crop-x/-y/-w/-h は呼び出し側が selection の attrs 経由で style
     属性に設定する(例: ImageCropper::x_percent() 等から組み立てた
     "--crop-x: 20%; --crop-y: 10%; --crop-w: 60%; --crop-h: 50%")。 */
  left: var(--crop-x, 0%);
  top: var(--crop-y, 0%);
  width: var(--crop-w, 100%);
  height: var(--crop-h, 100%);
  border: 1px solid #fff;
  box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.5);
}

[data-scope="image-cropper"][data-part="selection"]:focus-visible {
  outline: 2px solid #4a90d9;
  outline-offset: 2px;
}

[data-scope="image-cropper"][data-part="handle"] {
  position: absolute;
  width: 0.75rem;
  height: 0.75rem;
  background: #fff;
  border: 1px solid rgba(0, 0, 0, 0.25);
}

[data-scope="image-cropper"][data-part="handle"][data-position="se"] {
  top: 100%;
  left: 100%;
  cursor: nwse-resize;
}

[data-scope="image-cropper"][data-part="root"][data-disabled] {
  opacity: 0.5;
}

[data-scope="image-cropper"][data-part="grid"][data-axis="horizontal"] {
  /* 横方向のグリッド線のみを描く場合に使う。 */
}

Demo

枠線・余白は docs サイト側のデモ枠であり、fandhe-frontend-headless-ui 自体はスタイルを持ちません。

Sample photo to crop
Sample photo to crop

Features

  • root/viewport/image/selection/handle/grid の anatomy を持ち、矩形の crop 範囲(x/y/width/height)を値として保持する。
  • root は role="group" + aria-roledescription="image cropper" を固定付与する。ImageCropperProps に応じて root/viewport/selection/handle へ data-disabled、root/selection/grid へ data-dragging を出力する(イシュー #1610、参照実装〔ark-ui/zag.js〕突合)。
  • キーボード操作の受け口は handle ではなく selection(focusable な role="slider" + aria-roledescription="2d slider")へ集約される。aria-valuemin/aria-valuemax/aria-valuenow/aria-valuetext は crop 矩形の現在値から決定的に導出される(イシュー #1610)。
  • handle は role="presentation" + aria-hidden="true"(非 focusable)。data-position(旧 data-handle-position から改名)で 8 方位を表す(イシュー #1610)。
  • grid は aria-hidden="true"。GridAxis(Horizontal/Vertical)を渡すと data-axis を出力する(省略時は単一コンテナ、イシュー #1610)。
  • action_for_key(key, modifiers) はキーボード操作の対応表(Arrow = 移動、Alt+Arrow = SE ハンドル基準のリサイズ、Shift/Ctrl(Cmd) で step 拡大)を純粋関数として提供する。DOM への keydown 配線は wasm-full 側の後続責務のまま(イシュー #1610)。
  • canvas による実際のピクセル切り出し(画像処理)は本モジュールのスコープ外であり、crop 矩形の値を返すのみである。

Anatomy

root
  viewport
    image
  selection
    handle
  grid

API Reference

Arguments

NameTypeDefaultDescription
props&ImageCropperPropsImageCropperProps::default()disabled/dragging の状態束。root/viewport/selection/handle/grid 共通で受け取る(イシュー #1610)。
image(src, alt)&str, &str—対象画像の src/alt。既定エスケープを経由して出力される。
selection(state, props)&ImageCropper, &ImageCropperProps—crop 矩形の現在値(state)から aria-valuemax/aria-valuenow/aria-valuetext を決定的に導出する(イシュー #1610)。
handle(position, props)HandlePosition, &ImageCropperProps—方位(N/S/E/W/NE/NW/SE/SW)。data-position を出力する(旧 data-handle-position から改名)。
grid(axis, props)Option<GridAxis>, &ImageCropperPropsNoneSome のときのみ data-axis("horizontal"/"vertical")を出力する(イシュー #1610)。
action_for_key(key, modifiers)&str, KeyModifiers—KeyboardEvent.key 相当の文字列を ImageCropperAction へ写す純粋関数。未知キー・zoom キーは None(イシュー #1610)。
attrs / childrenVec<(&str, &str)> / Vec<Node>—各パーツ共通の追加属性・子ノード(代表 1 行に集約)。

Data Attributes

PartAttributeObserved Values
griddata-axishorizontal, vertical
griddata-dragging(値なし)
handledata-disabled(値なし)
handledata-positione, n, ne, nw, s, se, sw, w
rootdata-disabled(値なし)
rootdata-dragging(値なし)
selectiondata-disabled(値なし)
selectiondata-dragging(値なし)
viewportdata-disabled(値なし)

Examples

Two-handle selection

NE/SW の 2 ハンドルのみを持つ選択枠の組み立て例です。

role="group" の root と、role="slider" で focusable な selection に NE/SWの 2 個の handle(role="presentation" + aria-hidden)を組み込む例です。

Portrait photo to crop

Accessibility

Keyboard Interactions

KeyDescription
Tabselection パーツへフォーカスが移動する(disabled でなければ tabindex="0")。キーボード操作の受け口が handle から selection へ移った(イシュー #1610)。
ArrowLeft / ArrowRight / ArrowUp / ArrowDownaction_for_key が crop 矩形を Move(既定 step=1)。Shift 押下で step=10、Ctrl/Cmd 押下で step=50。DOM keydown 配線は wasm-full 側の後続責務のまま(イシュー #1610)。
Alt+Arrowaction_for_key が SE ハンドル基準の Resize を返す(イシュー #1610)。

WAI-ARIA

AttributeDescription
role="group" / aria-roledescriptionroot パーツへ "image cropper" を固定付与する。
role="presentation"viewport パーツへ固定付与する(イシュー #1610)。
role="slider" / aria-roledescription / aria-valuemin / aria-valuemax / aria-valuenow / aria-valuetextselection パーツへ付与する 2D slider 意味論。aria-valuetext は "x {x}, y {y}, width {width}, height {height}" の決定的な英語テンプレート(イシュー #1610)。
role="presentation" / aria-hidden="true"handle パーツへ固定付与する(非 focusable。旧実装の方位別 aria-label は既定では出力しない、イシュー #1610)。
aria-hidden="true"grid パーツへ固定付与する(装飾用、イシュー #1610)。