LWCでfileCardを実装する

AuraにはContentDocumentを表示する[fileCard](https://developer.salesforce.com/docs/component-library/bundle/lightning:fileCard/specification)というコンポーネントがありますが、LWCにはありません。
[ideas](https://ideas.salesforce.com/s/idea/a0B8W00000GdcxvUAB/lightning-web-component-for-lightningfilecard)には2020年から上がっていますが、採用されるかどうかも不明です。
であるならば、自分で作った方が良さそうです。

## AuraのfileCardについて

Auraの標準コンポーネントのfileCardは、LDS（Lightning Design System）の[file](https://www.lightningdesignsystem.com/components/files/)のデザインで、サムネイルとファイルアイコン、説明が表示されます。サムネイルをクリックするとプレビューが表示されます。
下記はAuraのfileCardの使用例です。

![スクリーンショット 2025-01-30 19.27.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125621/5dd9ac4c-9068-0d04-21c7-617b1af3e19f.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125621/1c26145c-3c69-5658-03e1-5c572ad8db5a.png)


```html
<lightning:fileCard fileId="069XXXXXXXXXXXXXXX" description="description"></lightning:fileCard>
```

## LWCでfileCardを実装する

HTMLとCSSは単にLDSの[file](https://www.lightningdesignsystem.com/components/files/)そのままです。

```html:fileCard.hhtml
<template>
    <div class="slds-file slds-file_card slds-has-title file-card">
        <figure>
            <a class="slds-file__crop" onclick={previewFile}>
                <span class="slds-assistive-text">Preview:</span>
                <img src={src} />
            </a>
            <figcaption class="slds-file__title slds-file__title_card">
                <div class="slds-media slds-media_small slds-media_center">
                    <div class="slds-media__figure slds-line-height_reset">
                        <lightning-icon icon-name={iconName} size="x-small"></lightning-icon>
                    </div>
                    <div class="slds-media__body">
                        <span class="slds-file__text slds-truncate" title={title}>{title}</span>
                    </div>
                </div>
            </figcaption>
        </figure>
    </div>
</template>
```

```css:fileCard.css
.file-card {
    width: 20rem;
}
.file-card img {
    max-height: 100%;
}
```

サムネイルには`/sfc/servlet.shepherd/version/renditionDownload?rendition={種別}&versionId={ContentVersionId}`を使用します。このURLにアクセスすることでContentVersionのプレビューを取得できます。

クリック時にはNavigationを使用してファイルを開きます。詳細は[こちら](https://developer.salesforce.com/docs/platform/ja-jp/lwc/guide/use-open-files.html)。

:::note warn
この記事で紹介するサーブレットURLは公式にサポートされているものではなく、予告なく変更される可能性があります。
:::

:::note warn
ExperienceサイトではfilePreviewへのナビゲーションはサポートされていません。
:::

```js:fileCard.js
import { LightningElement, api, wire } from "lwc";
import { NavigationMixin } from "lightning/navigation";
import { getRecord, getFieldValue } from "lightning/uiRecordApi";
import DOCUMENT_VERSION_ID_FIELD from "@salesforce/schema/ContentDocument.LatestPublishedVersionId";
import DOCUMENT_TITLE_FIELD from "@salesforce/schema/ContentDocument.Title";
import DOCUMENT_FILE_TYPE_FIELD from "@salesforce/schema/ContentDocument.FileType";
import getIconName from "./fileIcons.js";

const RENDITION = "THUMB240BY180";
const FIELDS = [DOCUMENT_VERSION_ID_FIELD, DOCUMENT_TITLE_FIELD, DOCUMENT_FILE_TYPE_FIELD];

/**
 * @typedef {Object} ContentDocument
 * @property {string} Id
 * @property {string} LatestPublishedVersionId
 * @property {string} Title
 * @prop {string} FileType
 */

/**
 * {@link https://www.lightningdesignsystem.com/components/files/}
 */
export default class FileCard extends NavigationMixin(LightningElement) {
    @api fileId;
    @api description;
    rendition = RENDITION;

    /** @type {ContentDocument} */
    @wire(getRecord, { recordId: "$fileId", fields: FIELDS })
    document;

    get title() {
        return this.description ? this.description : getFieldValue(this.document.data, DOCUMENT_TITLE_FIELD);
    }

    get versionId() {
        return getFieldValue(this.document.data, DOCUMENT_VERSION_ID_FIELD);
    }

    get fileType() {
        return getFieldValue(this.document.data, DOCUMENT_FILE_TYPE_FIELD);
    }

    get src() {
        return `/sfc/servlet.shepherd/version/renditionDownload?rendition=${this.rendition}&versionId=${this.versionId}&operationContext=CHATTER&contentId=${this.fileId}`;
    }

    get iconName() {
        return getIconName(this.fileType);
    }

    previewFile() {
        this[NavigationMixin.Navigate]({
            type: "standard__namedPage",
            attributes: {
                pageName: "filePreview"
            },
            state: {
                selectedRecordId: this.fileId
            }
        });
    }
}

```

ファイルアイコンはLDSの[icons](https://www.lightningdesignsystem.com/icons/#doctype)を使用します。

```js:fileIcons.js
/**
 * {@link https://www.lightningdesignsystem.com/icons/#doctype}
 */
const doctypeIcon = {
    CSV: "doctype:csv",
    EXCEL: "doctype:excel",
    IMAGE: "doctype:image",
    PDF: "doctype:pdf",
    PPT: "doctype:ppt",
    TXT: "doctype:txt",
    UNKNOWN: "doctype:unknown",
    WORD: "doctype:word",
    XML: "doctype:xml",
    ZIP: "doctype:zip"
};

export default function getIconName(fileType) {
    switch (fileType) {
        // PDF
        case "PDF":
            return doctypeIcon.PDF;
        // microsoft
        case "EXCEL":
        case "EXCEL_X":
            return doctypeIcon.EXCEL;
        case "WORD":
        case "WORD_X":
            return doctypeIcon.WORD;
        case "POWER_POINT":
        case "POWER_POINT_X":
            return doctypeIcon.PPT;
        // テキスト
        case "CSV":
            return doctypeIcon.CSV;
        case "JSON":
            return doctypeIcon.UNKNOWN;
        case "XML":
            return doctypeIcon.XML;
        case "TEXT":
            return doctypeIcon.TXT;
        // 画像
        case "IMAGE":
        case "GIF":
        case "JFIF":
        case "PNG":
            return doctypeIcon.IMAGE;
        // 書庫ファイル
        case "ZIP":
            return doctypeIcon.ZIP;
        // その他
        default:
            return doctypeIcon.UNKNOWN;
    }
}
```

## 参照
- [lightning:fileCard - Salesforce Lightning Component Library](https://developer.salesforce.com/docs/component-library/bundle/lightning:fileCard/documentation)
- [Files - Lightning Design System](https://www.lightningdesignsystem.com/components/files/)