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 はこれを内部で一元的に組み立てます)。
[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 自体はスタイルを持ちません。
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
gridAPI Reference
Arguments
| Name | Type | Default | Description |
|---|---|---|---|
props | &ImageCropperProps | ImageCropperProps::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>, &ImageCropperProps | None | Some のときのみ data-axis("horizontal"/"vertical")を出力する(イシュー #1610)。 |
action_for_key(key, modifiers) | &str, KeyModifiers | — | KeyboardEvent.key 相当の文字列を ImageCropperAction へ写す純粋関数。未知キー・zoom キーは None(イシュー #1610)。 |
attrs / children | Vec<(&str, &str)> / Vec<Node> | — | 各パーツ共通の追加属性・子ノード(代表 1 行に集約)。 |
Data Attributes
| Part | Attribute | Observed Values |
|---|---|---|
grid | data-axis | horizontal, vertical |
grid | data-dragging | (値なし) |
handle | data-disabled | (値なし) |
handle | data-position | e, n, ne, nw, s, se, sw, w |
root | data-disabled | (値なし) |
root | data-dragging | (値なし) |
selection | data-disabled | (値なし) |
selection | data-dragging | (値なし) |
viewport | data-disabled | (値なし) |
Examples
Two-handle selection
NE/SW の 2 ハンドルのみを持つ選択枠の組み立て例です。
role="group" の root と、role="slider" で focusable な selection に NE/SWの 2 個の handle(role="presentation" + aria-hidden)を組み込む例です。
Accessibility
Keyboard Interactions
| Key | Description |
|---|---|
| Tab | selection パーツへフォーカスが移動する(disabled でなければ tabindex="0")。キーボード操作の受け口が handle から selection へ移った(イシュー #1610)。 |
| ArrowLeft / ArrowRight / ArrowUp / ArrowDown | action_for_key が crop 矩形を Move(既定 step=1)。Shift 押下で step=10、Ctrl/Cmd 押下で step=50。DOM keydown 配線は wasm-full 側の後続責務のまま(イシュー #1610)。 |
| Alt+Arrow | action_for_key が SE ハンドル基準の Resize を返す(イシュー #1610)。 |
WAI-ARIA
| Attribute | Description |
|---|---|
| role="group" / aria-roledescription | root パーツへ "image cropper" を固定付与する。 |
| role="presentation" | viewport パーツへ固定付与する(イシュー #1610)。 |
| role="slider" / aria-roledescription / aria-valuemin / aria-valuemax / aria-valuenow / aria-valuetext | selection パーツへ付与する 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)。 |