@@ -24,6 +24,10 @@ const MANUAL_SCHEMA = [
2424 { name : "media_content_type" , required : false , selector : { text : { } } } ,
2525] as const ;
2626
27+ const INCLUDE_DOMAINS = [ "media_player" ] ;
28+
29+ const EMPTY_FORM = { } ;
30+
2731@customElement ( "ha-selector-media" )
2832export class HaMediaSelector extends LitElement {
2933 @property ( { attribute : false } ) public hass ! : HomeAssistant ;
@@ -84,7 +88,7 @@ export class HaMediaSelector extends LitElement {
8488 ( stateObj &&
8589 supportsFeature ( stateObj , MediaPlayerEntityFeature . BROWSE_MEDIA ) ) ;
8690
87- const hasAccept = this . selector . media ?. accept ?. length ;
91+ const hasAccept = this . selector ? .media ?. accept ?. length ;
8892
8993 return html `
9094 ${ hasAccept
@@ -100,7 +104,7 @@ export class HaMediaSelector extends LitElement {
100104 .disabled = ${ this . disabled }
101105 .helper = ${ this . helper }
102106 .required = ${ this . required }
103- include - domains = '["media_player"]'
107+ . includeDomains = ${ INCLUDE_DOMAINS }
104108 allow- custo m- entity
105109 @value-changed = ${ this . _entityChanged }
106110 > </ ha- entity- picker>
@@ -114,71 +118,70 @@ export class HaMediaSelector extends LitElement {
114118 </ ha- alert>
115119 <ha- for m
116120 .hass = ${ this . hass }
117- .data = ${ this . value }
121+ .data = ${ this . value || EMPTY_FORM }
118122 .schema = ${ MANUAL_SCHEMA }
119123 .computeLabel = ${ this . _computeLabelCallback }
120124 > </ ha- for m>
121125 `
122126 : html `
123127 <ha- card
124128 outlined
129+ tabindex= "0"
130+ role = "butto n"
131+ aria- label= ${ ! this . value ?. media_content_id
132+ ? this . hass . localize ( "ui.components.selectors.media.pick_media" )
133+ : this . value . metadata ?. title || this . value . media_content_id }
125134 @click = ${ this . _pickMedia }
135+ @keydown = ${ this . _handleKeyDown }
126136 class= ${ this . disabled || ( ! this . value ?. entity_id && ! hasAccept )
127137 ? "disabled"
128138 : "" }
129139 >
130- <div
131- class= "thumbnail ${ classMap ( {
132- portrait :
133- ! ! this . value ?. metadata ?. media_class &&
134- MediaClassBrowserSettings [
135- this . value . metadata . children_media_class ||
136- this . value . metadata . media_class
137- ] . thumbnail_ratio === "portrait" ,
138- } ) } "
139- >
140- ${ this . value ?. metadata ?. thumbnail
141- ? html `
142- <div
143- class= "${ classMap ( {
144- "centered-image" :
145- ! ! this . value . metadata . media_class &&
146- [ "app" , "directory" ] . includes (
147- this . value . metadata . media_class
148- ) ,
149- } ) }
150- image"
151- style = ${ this . _thumbnailUrl
152- ? `background-image: url(${ this . _thumbnailUrl } );`
153- : "" }
154- > </ div>
155- `
156- : html `
157- <div class= "icon-holder image" >
158- <ha- svg- icon
159- class= "folder"
160- .path = ${ ! this . value ?. media_content_id
161- ? mdiPlus
162- : this . value ?. metadata ?. media_class
163- ? MediaClassBrowserSettings [
164- this . value . metadata . media_class ===
165- "directory"
166- ? this . value . metadata
167- . children_media_class ||
168- this . value . metadata . media_class
169- : this . value . metadata . media_class
170- ] . icon
171- : mdiPlayBox }
172- > </ ha- svg- icon>
173- </ div>
174- ` }
175- </ div>
176- <div class= "title" >
177- ${ ! this . value ?. media_content_id
178- ? this . hass . localize (
179- "ui.components.selectors.media.pick_media"
180- )
181- : this . value . metadata ?. title || this . value . media_content_id }
140+ <div class= "content-container" >
141+ <div class= "thumbnail" >
142+ ${ this . value ?. metadata ?. thumbnail
143+ ? html `
144+ <div
145+ class= "${ classMap ( {
146+ "centered-image" :
147+ ! ! this . value . metadata . media_class &&
148+ [ "app" , "directory" ] . includes (
149+ this . value . metadata . media_class
150+ ) ,
151+ } ) }
152+ image"
153+ style = ${ this . _thumbnailUrl
154+ ? `background-image: url(${ this . _thumbnailUrl } );`
155+ : "" }
156+ > </ div>
157+ `
158+ : html `
159+ <div class= "icon-holder image" >
160+ <ha- svg- icon
161+ class= "folder"
162+ .path = ${ ! this . value ?. media_content_id
163+ ? mdiPlus
164+ : this . value ?. metadata ?. media_class
165+ ? MediaClassBrowserSettings [
166+ this . value . metadata . media_class ===
167+ "directory"
168+ ? this . value . metadata
169+ . children_media_class ||
170+ this . value . metadata . media_class
171+ : this . value . metadata . media_class
172+ ] . icon
173+ : mdiPlayBox }
174+ > </ ha- svg- icon>
175+ </ div>
176+ ` }
177+ </ div>
178+ <div class= "title" >
179+ ${ ! this . value ?. media_content_id
180+ ? this . hass . localize (
181+ "ui.components.selectors.media.pick_media"
182+ )
183+ : this . value . metadata ?. title || this . value . media_content_id }
184+ </ div>
182185 </ div>
183186 </ ha- card>
184187 ` }
@@ -229,6 +232,13 @@ export class HaMediaSelector extends LitElement {
229232 } ) ;
230233 }
231234
235+ private _handleKeyDown ( ev : KeyboardEvent ) {
236+ if ( ev . key === "Enter" || ev . key === " " ) {
237+ ev . preventDefault ( ) ;
238+ this . _pickMedia ( ) ;
239+ }
240+ }
241+
232242 static styles = css `
233243 ha-entity-picker {
234244 display : block;
@@ -243,41 +253,52 @@ export class HaMediaSelector extends LitElement {
243253 }
244254 ha-card {
245255 position : relative;
246- width : 200 px ;
256+ width : 100 % ;
247257 box-sizing : border-box;
248258 cursor : pointer;
259+ transition : background-color 180ms ease-in-out;
260+ min-height : 56px ;
261+ }
262+ ha-card : hover : not (.disabled ),
263+ ha-card : focus : not (.disabled ) {
264+ background-color : var (--state-icon-hover-color , rgba (0 , 0 , 0 , 0.04 ));
265+ }
266+ ha-card : focus {
267+ outline : none;
249268 }
250269 ha-card .disabled {
251270 pointer-events : none;
252271 color : var (--disabled-text-color );
253272 }
273+ .content-container {
274+ display : flex;
275+ align-items : center;
276+ padding : 8px ;
277+ gap : 12px ;
278+ }
254279 ha-card .thumbnail {
255- width : 100% ;
280+ width : 40px ;
281+ height : 40px ;
282+ flex-shrink : 0 ;
256283 position : relative;
257284 box-sizing : border-box;
258- transition : padding-bottom 0.1s ease-out;
259- padding-bottom : 100% ;
260- }
261- ha-card .thumbnail .portrait {
262- padding-bottom : 150% ;
285+ border-radius : 8px ;
286+ overflow : hidden;
263287 }
264288 ha-card .image {
265- border-radius : 3 px 3 px 0 0 ;
289+ border-radius : 8 px ;
266290 }
267291 .folder {
268- --mdc-icon-size : calc ( var ( --media-browse-item-size , 175 px ) * 0.4 ) ;
292+ --mdc-icon-size : 24 px ;
269293 }
270294 .title {
271- font-size : var (--ha-font-size-l );
272- padding-top : 16px ;
295+ font-size : var (--ha-font-size-m );
273296 overflow : hidden;
274297 text-overflow : ellipsis;
275- margin-bottom : 16px ;
276- padding-left : 16px ;
277- padding-right : 4px ;
278- padding-inline-start : 16px ;
279- padding-inline-end : 4px ;
280298 white-space : nowrap;
299+ line-height : 1.4 ;
300+ flex : 1 ;
301+ min-width : 0 ;
281302 }
282303 .image {
283304 position : absolute;
@@ -290,13 +311,15 @@ export class HaMediaSelector extends LitElement {
290311 background-position : center;
291312 }
292313 .centered-image {
293- margin : 0 8 px ;
314+ margin : 4 px ;
294315 background-size : contain;
295316 }
296317 .icon-holder {
297318 display : flex;
298319 justify-content : center;
299320 align-items : center;
321+ width : 100% ;
322+ height : 100% ;
300323 }
301324 ` ;
302325}
0 commit comments