feat: keyboard-navigate Custom tab tiles

Wire the Custom tab into the picker's arrow-key navigation: Text, Avatar,
and Image tiles now gain a blue ring when highlighted by keyboard and
commit on Enter, matching Icons/Emojis.

custom-tab-cp destructures the already-plumbed :highlighted-id from opts
and emits data-item-id + conditional .is-highlighted on each button. CSS
neutralizes the generic button.is-highlighted (which would paint the
label column) and moves the ring onto the 48x48 preview child. A
baseline transparent outline avoids the currentColor flash when the ring
appears.
This commit is contained in:
scheinriese
2026-04-23 14:42:05 +02:00
parent 407308fe64
commit 7ec9fcbafc
2 changed files with 39 additions and 4 deletions

View File

@@ -1571,12 +1571,16 @@
:data {:value avatar-value
:backgroundColor backgroundColor
:color color}})
on-chosen (:on-chosen opts)]
on-chosen (:on-chosen opts)
highlighted-id (:highlighted-id opts)]
[:div.custom-tab-content
;; Text option
(when text-item
[:button.custom-tab-item
{:on-click #(reset! *view :text-picker)}
{:data-item-id "custom-text"
:tabIndex "-1"
:class (when (= "custom-text" highlighted-id) "is-highlighted")
:on-click #(reset! *view :text-picker)}
[:div.custom-tab-item-preview
(icon text-item {:size 24})]
[:span.custom-tab-item-label "Text"]])
@@ -1584,14 +1588,20 @@
;; Avatar option
(when avatar-item
[:button.custom-tab-item
{:on-click #(on-chosen % avatar-item)}
{:data-item-id "custom-avatar"
:tabIndex "-1"
:class (when (= "custom-avatar" highlighted-id) "is-highlighted")
:on-click #(on-chosen % avatar-item)}
[:div.custom-tab-item-preview
(icon avatar-item {:size 24})]
[:span.custom-tab-item-label "Avatar"]])
;; Image option — always show dashed placeholder with camera icon
[:button.custom-tab-item
{:on-click #(reset! *view :asset-picker)}
{:data-item-id "custom-image"
:tabIndex "-1"
:class (when (= "custom-image" highlighted-id) "is-highlighted")
:on-click #(reset! *view :asset-picker)}
[:div.custom-tab-item-preview
[:span.image-tile-placeholder
{:style {:width 28

View File

@@ -430,15 +430,40 @@
@apply transition-all duration-150;
border: 1px solid var(--rx-gray-06);
background-color: var(--rx-gray-03);
/* Baseline transparent outline so outline-color can transition
transparent → accent without the browser's currentColor flashing
through during the discrete style/width jump. */
outline: 2px solid transparent;
outline-offset: -2px;
&:hover {
border-color: var(--rx-accent-09);
}
}
/* Keyboard-nav highlight for custom tiles: neutralize the generic
button.is-highlighted rule (which paints the full column including
the label) and move the ring onto the 48x48 preview child instead. */
.cp__emoji-icon-picker button.custom-tab-item.is-highlighted {
background-color: transparent !important;
outline: none;
border-radius: 0 !important;
}
.cp__emoji-icon-picker button.custom-tab-item.is-highlighted .custom-tab-item-preview {
background-color: var(--lx-accent-04);
outline: 2px solid var(--lx-accent-09);
outline-offset: -2px;
}
.cp__emoji-icon-picker button.custom-tab-item.is-highlighted .custom-tab-item-label {
color: var(--lx-accent-11);
}
.custom-tab-item-label {
@apply text-xs;
color: var(--rx-gray-11);
transition: color 150ms;
}
/* Shared drag overlay hint — used by both icon picker and asset picker */