import { CSSResultArray , html , PropertyValues , SizedMixin , SpectrumElement , TemplateResult , } from '@spectrum-web-components/base' ; import { ifDefined } from '@spectrum-web-components/base/src/directives.js' ; import { property , query , } from '@spectrum-web-components/base/src/decorators.js' ; import { FocusVisiblePolyfillMixin } from '@spectrum-web-components/shared/src/focus-visible.js' ; import { ObserveSlotPresence } from '@spectrum-web-components/shared/src/observe-slot-presence.js' ; import { LikeAnchor } from '@spectrum-web-components/shared/src/like-anchor.js' ; import '@spectrum-web-components/asset/sp-asset.js' ; import { Checkbox } from '@spectrum-web-components/checkbox/src/Checkbox' ; import '@spectrum-web-components/checkbox/sp-checkbox.js' ; import '@spectrum-web-components/quick-actions/sp-quick-actions.js' ; import cardStyles from './card.css.js' ; import headingStyles from '@spectrum-web-components/styles/heading.js' ; import detailStyles from '@spectrum-web-components/styles/detail.js' ; element fires slot slot slot slot slot slot slot export class Card extends LikeAnchor ( SizedMixin ( ObserveSlotPresence ( FocusVisiblePolyfillMixin ( SpectrumElement ) , [ '[slot="cover-photo"]' , '[slot="preview"]' , ] ) , { validSizes : [ 's' , 'm' ] , } ) ) { public static get styles ( ) : CSSResultArray { return [ headingStyles , detailStyles , cardStyles ] ; } @ property ( ) public asset ? : 'file' | 'folder' ; @ property ( { reflect : true } ) public variant : 'standard' | 'gallery' | 'quiet' = 'standard' ; @ property ( { type : Boolean , reflect : true } ) public selected = false ; @ property ( ) public heading = '' ; @ property ( { type : Boolean , reflect : true } ) public horizontal = false ; @ query ( '#like-anchor' ) private likeAnchor ? : HTMLAnchorElement ; @ property ( { type : Boolean , reflect : true } ) public focused = false ; @ property ( { type : Boolean , reflect : true } ) public toggles = false ; @ property ( ) public subheading = '' ; protected get hasCoverPhoto ( ) : boolean { return this . getSlotContentPresence ( '[slot="cover-photo"]' ) ; } protected get hasPreview ( ) : boolean { return this . getSlotContentPresence ( '[slot="preview"]' ) ; } public click ( ) { this . likeAnchor ?. click ( ) ; } private handleFocusin = ( event ) : void => { this . focused = true ; const target = event . composedPath ( ) [ 0 ] ; if ( target !== this ) { this . removeEventListener ( 'keydown' , this . handleKeydown ) ; return ; } this . addEventListener ( 'keydown' , this . handleKeydown ) ; } ; private handleFocusout ( event ) { this . focused = false ; const target = event . composedPath ( ) [ 0 ] ; if ( target === this ) { this . removeEventListener ( 'keydown' , this . handleKeydown ) ; } } private handleKeydown ( event ) { const { code } = event ; switch ( code ) { case 'Space' : this . toggleSelected ( ) ; if ( this . toggles ) { break ; } case 'Enter' : case 'NumpadEnter' : this . click ( ) ; } } private handleSelectedChange ( { target : { checked } , } ) { this . selected = checked ; this . announceChange ( ) ; } public toggleSelected ( ) { if ( ! this . toggles ) { this . dispatchEvent ( new Event ( 'click' , { bubbles : true , composed : true , } ) ) ; return ; } this . selected = ! this . selected ; this . announceChange ( ) ; } private announceChange ( ) { const applyDefault = this . dispatchEvent ( new Event ( 'change' , { cancelable : true , } ) ) ; if ( ! applyDefault ) { this . selected = ! this . selected ; } } private stopPropagationOnHref ( event ) { if ( this . href ) { event . stopPropagation ( ) ; } } private handlePointerdown ( event ) { const path = event . composedPath ( ) ; const hasAnchor = path . some ( ( el ) => ( el as HTMLElement ) . localName === 'a' ) ; if ( hasAnchor ) return ; const start = + new Date ( ) ; const handleEnd = ( ) : void => { const end = + new Date ( ) ; if ( end - start < 200 ) { this . click ( ) ; } this . removeEventListener ( 'pointerup' , handleEnd ) ; } ; this . addEventListener ( 'pointerup' , handleEnd ) ; } protected get renderHeading ( ) : TemplateResult { return html `
            <div
                class="title spectrum-Heading spectrum-Heading--sizeXS"
                id="heading"
            >
                <slot name="heading">${ this . heading }</slot>
            </div>
        ` ; } protected get renderPreviewImage ( ) : TemplateResult { return html `
            <sp-asset id="preview" variant=${ ifDefined ( this . asset ) }>
                <slot name="preview"></slot>
            </sp-asset>
        ` ; } protected get renderCoverImage ( ) : TemplateResult { return html `
            <sp-asset id="cover-photo" variant=${ ifDefined ( this . asset ) }>
                <slot name="cover-photo"></slot>
            </sp-asset>
        ` ; } protected get images ( ) : TemplateResult [ ] { const images = [ ] ; if ( this . hasPreview ) images . push ( this . renderPreviewImage ) ; if ( this . hasCoverPhoto ) images . push ( this . renderCoverImage ) ; return images ; } private renderImage ( ) { if ( this . horizontal ) { return this . images ; } if ( this . variant !== 'standard' ) { return [ this . renderPreviewImage ] ; } return this . images ; } private get renderSubtitleAndDescription ( ) : TemplateResult { return html `
            <div class="subtitle spectrum-Detail spectrum-Detail--sizeS">
                <slot name="subheading">${ this . subheading }</slot>
            </div>
            <slot name="description"></slot>
        ` ; } protected render ( ) { return html `
            <div class="body">
                <div class="header">
                    ${ this . renderHeading }
                    ${ this . variant === 'gallery' ? this . renderSubtitleAndDescription : html `` }
                    ${ this . variant !== 'quiet' || this . size !== 's' ? html `
                              <div
                                  class="action-button"
                                  @pointerdown=${ this . stopPropagationOnHref }
                              >
                                  <slot name="actions"></slot>
                              </div>
                          ` : html `` }
                </div>
                ${ this . variant !== 'gallery' ? html `
                          <div class="content">
                              ${ this . renderSubtitleAndDescription }
                          </div>
                      ` : html `` }
            </div>
            ${ this . href ? this . renderAnchor ( { id : 'like-anchor' , labelledby : 'heading' , } ) : html `` }
            ${ this . variant === 'standard' ? html `
                      <slot name="footer"></slot>
                  ` : html `` }
            ${ this . renderImage ( ) }
            ${ this . toggles ? html `
                      <sp-quick-actions
                          class="quick-actions"
                          @pointerdown=${ this . stopPropagationOnHref }
                      >
                          <sp-checkbox
                              class="checkbox"
                              @change=${ this . handleSelectedChange }
                              ?checked=${ this . selected }
                          ></sp-checkbox>
                      </sp-quick-actions>
                  ` : html `` }
            ${ this . variant === 'quiet' && this . size === 's' ? html `
                      <sp-quick-actions
                          class="spectrum-QuickActions actions"
                          @pointerdown=${ this . stopPropagationOnHref }
                      >
                          <slot name="actions"></slot>
                      </sp-quick-actions>
                  ` : html `` }
        ` ; } protected firstUpdated ( changes ) { super . firstUpdated ( changes ) ; this . addEventListener ( 'pointerdown' , this . handlePointerdown ) ; this . addEventListener ( 'focusin' , this . handleFocusin ) ; this . shadowRoot . addEventListener ( 'focusin' , this . handleFocusin ) ; this . addEventListener ( 'focusout' , this . handleFocusout ) ; } }