Skip to content

Commit

Permalink
Feat(web): Extend FileUploaderAttachment with preview and custom ac…
Browse files Browse the repository at this point in the history
…tions slot
  • Loading branch information
adamkudrna committed Jul 27, 2023
1 parent b40a8d9 commit 768906f
Show file tree
Hide file tree
Showing 10 changed files with 424 additions and 61 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ const FileUploaderAttachment = (props: SpiritFileUploaderAttachmentProps) => {
className={classNames(classProps.attachment.root, styleProps.className)}
>
<Icon name={iconName} aria-hidden="true" />
<span className="text-truncate">{label}</span>
<span className={classProps.attachment.name}>
<span className="text-truncate">{label}</span>
</span>
<AttachmentDismissButton onClick={dismissHandler}>{buttonLabel}</AttachmentDismissButton>
</li>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ describe('useFileUploaderStyleProps', () => {
expect(result.current.classProps.list).toBe('FileUploaderList');
expect(result.current.classProps.attachment).toBeDefined();
expect(result.current.classProps.attachment.root).toBe('FileUploaderAttachment');
expect(result.current.classProps.attachment.button).toBe('FileUploaderAttachment__remove');
expect(result.current.classProps.attachment.button).toBe('FileUploaderAttachment__action');
});

it('should return disabled', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export interface FileUploaderStyleReturn {
attachment: {
root: string;
button: string;
name: string;
};
};
}
Expand All @@ -60,7 +61,8 @@ export const useFileUploaderStyleProps = (props?: FileUploaderStyleProps): FileU
const fileUploaderInputValidationTextClass = `${fileUploaderInputClass}__validationText`;
const fileUploaderListClass = `${fileUploaderClass}List`;
const fileUploaderAttachmentClass = `${fileUploaderClass}Attachment`;
const fileUploaderAttachmentButtonClass = `${fileUploaderAttachmentClass}__remove`;
const fileUploaderAttachmentNameClass = `${fileUploaderAttachmentClass}__name`;
const fileUploaderAttachmentButtonClass = `${fileUploaderAttachmentClass}__action`;

return {
classProps: {
Expand Down Expand Up @@ -92,6 +94,7 @@ export const useFileUploaderStyleProps = (props?: FileUploaderStyleProps): FileU
attachment: {
root: fileUploaderAttachmentClass,
button: fileUploaderAttachmentButtonClass,
name: fileUploaderAttachmentNameClass,
},
},
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@

{# Class names #}
{%- set _rootClassName = _spiritClassPrefix ~ 'FileUploaderAttachment' -%}
{%- set _removeClassName = _spiritClassPrefix ~ 'FileUploaderAttachment__remove' -%}
{%- set _nameClassName = _spiritClassPrefix ~ 'FileUploaderAttachment__name' -%}
{%- set _removeClassName = _spiritClassPrefix ~ 'FileUploaderAttachment__action' -%}

{# Miscellaneous #}
{%- set _styleProps = useStyleProps(props) -%}
Expand All @@ -19,9 +20,11 @@
{{ styleProp(_styleProps) }}
data-spirit-populate-field="item"
>
<Icon name="{{ _iconName }}" isReusable={ false }/>
<span class="text-truncate" data-spirit-populate-field="name">
{{- _fileName -}}
<Icon name="{{ _iconName }}" isReusable={ false } />
<span class="{{ _nameClassName }}">
<span class="text-truncate" data-spirit-populate-field="name">
{{- _fileName -}}
</span>
</span>
<button
type="button"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<li class="FileUploaderAttachment" data-spirit-populate-field="item">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewbox="0 0 24 24" fill="none" aria-hidden="true">
<path d="M6 22C5.45 22 4.97917 21.8042 4.5875 21.4125C4.19583 21.0208 4 20.55 4 20V4C4 3.45 4.19583 2.97917 4.5875 2.5875C4.97917 2.19583 5.45 2 6 2H13.175C13.4417 2 13.6958 2.05 13.9375 2.15C14.1792 2.25 14.3917 2.39167 14.575 2.575L19.425 7.425C19.6083 7.60833 19.75 7.82083 19.85 8.0625C19.95 8.30417 20 8.55833 20 8.825V20C20 20.55 19.8042 21.0208 19.4125 21.4125C19.0208 21.8042 18.55 22 18 22H6ZM12 9V4H6V20H18V10H13C12.7167 10 12.4792 9.90417 12.2875 9.7125C12.0958 9.52083 12 9.28333 12 9Z" fill="#132930">
</path></svg> <button type="button" class="FileUploaderAttachment__remove" data-spirit-populate-field="button"><span class="accessibility-hidden">Remove</span> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewbox="0 0 24 24" fill="none" aria-hidden="true">
</path></svg> <button type="button" class="FileUploaderAttachment__action" data-spirit-populate-field="button"><span class="accessibility-hidden">Remove</span> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewbox="0 0 24 24" fill="none" aria-hidden="true">
<path d="M18.3 5.70997C17.91 5.31997 17.28 5.31997 16.89 5.70997L12 10.59L7.11 5.69997C6.72 5.30997 6.09 5.30997 5.7 5.69997C5.31 6.08997 5.31 6.71997 5.7 7.10997L10.59 12L5.7 16.89C5.31 17.28 5.31 17.91 5.7 18.3C6.09 18.69 6.72 18.69 7.11 18.3L12 13.41L16.89 18.3C17.28 18.69 17.91 18.69 18.3 18.3C18.69 17.91 18.69 17.28 18.3 16.89L13.41 12L18.3 7.10997C18.68 6.72997 18.68 6.08997 18.3 5.70997Z" fill="#132930">
</path></svg></button>
</li>
Expand All @@ -17,7 +17,7 @@
<li class="FileUploaderAttachment" data-spirit-populate-field="item">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewbox="0 0 24 24" fill="none" aria-hidden="true">
<path d="M18 13H13V18C13 18.55 12.55 19 12 19C11.45 19 11 18.55 11 18V13H6C5.45 13 5 12.55 5 12C5 11.45 5.45 11 6 11H11V6C11 5.45 11.45 5 12 5C12.55 5 13 5.45 13 6V11H18C18.55 11 19 11.45 19 12C19 12.55 18.55 13 18 13Z" fill="#132930">
</path></svg> <span class="text-truncate" data-spirit-populate-field="name">file.pdf</span> <button type="button" class="FileUploaderAttachment__remove" data-spirit-populate-field="button"><span class="accessibility-hidden">Delete</span> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewbox="0 0 24 24" fill="none" aria-hidden="true">
</path></svg> <span class="FileUploaderAttachment__name"><span class="text-truncate" data-spirit-populate-field="name">file.pdf</span></span> <button type="button" class="FileUploaderAttachment__action" data-spirit-populate-field="button"><span class="accessibility-hidden">Delete</span> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewbox="0 0 24 24" fill="none" aria-hidden="true">
<path d="M18.3 5.70997C17.91 5.31997 17.28 5.31997 16.89 5.70997L12 10.59L7.11 5.69997C6.72 5.30997 6.09 5.30997 5.7 5.69997C5.31 6.08997 5.31 6.71997 5.7 7.10997L10.59 12L5.7 16.89C5.31 17.28 5.31 17.91 5.7 18.3C6.09 18.69 6.72 18.69 7.11 18.3L12 13.41L16.89 18.3C17.28 18.69 17.91 18.69 18.3 18.3C18.69 17.91 18.69 17.28 18.3 16.89L13.41 12L18.3 7.10997C18.68 6.72997 18.68 6.08997 18.3 5.70997Z" fill="#132930">
</path></svg></button>
</li>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<li class="FileUploaderAttachment" data-spirit-populate-field="item">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewbox="0 0 24 24" fill="none" aria-hidden="true">
<path d="M6 22C5.45 22 4.97917 21.8042 4.5875 21.4125C4.19583 21.0208 4 20.55 4 20V4C4 3.45 4.19583 2.97917 4.5875 2.5875C4.97917 2.19583 5.45 2 6 2H13.175C13.4417 2 13.6958 2.05 13.9375 2.15C14.1792 2.25 14.3917 2.39167 14.575 2.575L19.425 7.425C19.6083 7.60833 19.75 7.82083 19.85 8.0625C19.95 8.30417 20 8.55833 20 8.825V20C20 20.55 19.8042 21.0208 19.4125 21.4125C19.0208 21.8042 18.55 22 18 22H6ZM12 9V4H6V20H18V10H13C12.7167 10 12.4792 9.90417 12.2875 9.7125C12.0958 9.52083 12 9.28333 12 9Z" fill="#132930">
</path></svg> <button type="button" class="FileUploaderAttachment__remove" data-spirit-populate-field="button"><span class="accessibility-hidden">Remove</span> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewbox="0 0 24 24" fill="none" aria-hidden="true">
</path></svg> <button type="button" class="FileUploaderAttachment__action" data-spirit-populate-field="button"><span class="accessibility-hidden">Remove</span> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewbox="0 0 24 24" fill="none" aria-hidden="true">
<path d="M18.3 5.70997C17.91 5.31997 17.28 5.31997 16.89 5.70997L12 10.59L7.11 5.69997C6.72 5.30997 6.09 5.30997 5.7 5.69997C5.31 6.08997 5.31 6.71997 5.7 7.10997L10.59 12L5.7 16.89C5.31 17.28 5.31 17.91 5.7 18.3C6.09 18.69 6.72 18.69 7.11 18.3L12 13.41L16.89 18.3C17.28 18.69 17.91 18.69 18.3 18.3C18.69 17.91 18.69 17.28 18.3 16.89L13.41 12L18.3 7.10997C18.68 6.72997 18.68 6.08997 18.3 5.70997Z" fill="#132930">
</path></svg></button>
</li>
Expand All @@ -37,7 +37,7 @@ <h3 id="file-uploader-attachments" hidden="">
<li class="FileUploaderAttachment" data-spirit-populate-field="item">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewbox="0 0 24 24" fill="none" aria-hidden="true">
<path d="M6 22C5.45 22 4.97917 21.8042 4.5875 21.4125C4.19583 21.0208 4 20.55 4 20V4C4 3.45 4.19583 2.97917 4.5875 2.5875C4.97917 2.19583 5.45 2 6 2H13.175C13.4417 2 13.6958 2.05 13.9375 2.15C14.1792 2.25 14.3917 2.39167 14.575 2.575L19.425 7.425C19.6083 7.60833 19.75 7.82083 19.85 8.0625C19.95 8.30417 20 8.55833 20 8.825V20C20 20.55 19.8042 21.0208 19.4125 21.4125C19.0208 21.8042 18.55 22 18 22H6ZM12 9V4H6V20H18V10H13C12.7167 10 12.4792 9.90417 12.2875 9.7125C12.0958 9.52083 12 9.28333 12 9Z" fill="#132930">
</path></svg> <button type="button" class="FileUploaderAttachment__remove" data-spirit-populate-field="button"><span class="accessibility-hidden">Remove</span> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewbox="0 0 24 24" fill="none" aria-hidden="true">
</path></svg> <button type="button" class="FileUploaderAttachment__action" data-spirit-populate-field="button"><span class="accessibility-hidden">Remove</span> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewbox="0 0 24 24" fill="none" aria-hidden="true">
<path d="M18.3 5.70997C17.91 5.31997 17.28 5.31997 16.89 5.70997L12 10.59L7.11 5.69997C6.72 5.30997 6.09 5.30997 5.7 5.69997C5.31 6.08997 5.31 6.71997 5.7 7.10997L10.59 12L5.7 16.89C5.31 17.28 5.31 17.91 5.7 18.3C6.09 18.69 6.72 18.69 7.11 18.3L12 13.41L16.89 18.3C17.28 18.69 17.91 18.69 18.3 18.3C18.69 17.91 18.69 17.28 18.3 16.89L13.41 12L18.3 7.10997C18.68 6.72997 18.68 6.08997 18.3 5.70997Z" fill="#132930">
</path></svg></button>
</li>
Expand Down
163 changes: 151 additions & 12 deletions packages/web/src/scss/components/FileUploader/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -283,11 +283,16 @@ truncated.

```html
<li class="FileUploaderAttachment">
<!-- File icon: -->
<svg width="24" height="24" aria-hidden="true">
<use xlink:href="/icons/svg/sprite.svg#file" />
</svg>
<span class="text-truncate">My resume.docx</span>
<button type="button" class="FileUploaderAttachment__remove">
<!-- File name: -->
<span class="FileUploaderAttachment__name">
<span class="text-truncate">My resume.docx</span>
</span>
<!-- Remove button: -->
<button type="button" class="FileUploaderAttachment__action">
<span class="accessibility-hidden">Remove</span>
<svg width="24" height="24" aria-hidden="true">
<use xlink:href="/icons/svg/sprite.svg#close" />
Expand All @@ -298,8 +303,8 @@ truncated.

While you may insert FileUploaderAttachment into your FileUploaderList, in typical use cases it will live inside a
[`<template>`][mdn-template] tag in the parent FileUploader. The `<template>` tag must be inserted inside the main
wrapper element that has the `data-spirit-toggle="fileUploader"` attribute. Our JavaScript FileUploader plugin will then pick
up the template and apply it on any attachments the user wants to upload.
wrapper element that has the `data-spirit-toggle="fileUploader"` attribute. Our JavaScript FileUploader plugin will then
pick up the template and apply it on any attachments the user wants to upload.

```html
<div class="FileUploader" data-spirit-toggle="fileUploader">
Expand All @@ -308,8 +313,10 @@ up the template and apply it on any attachments the user wants to upload.
<svg width="24" height="24" aria-hidden="true">
<use xlink:href="/icons/svg/sprite.svg#file" />
</svg>
<span class="text-truncate" data-spirit-populate-field="name">File name</span>
<button type="button" class="FileUploaderAttachment__remove" data-spirit-populate-field="button">
<span class="FileUploaderAttachment__name">
<span class="text-truncate" data-spirit-populate-field="name">File name</span>
</span>
<button type="button" class="FileUploaderAttachment__action" data-spirit-populate-field="button">
<span class="accessibility-hidden">Remove</span>
<svg width="24" height="24" aria-hidden="true">
<use xlink:href="/icons/svg/sprite.svg#close" />
Expand All @@ -322,6 +329,134 @@ up the template and apply it on any attachments the user wants to upload.
</div>
```

### Preview Image

You can add a preview image to the FileUploaderAttachment.

```html
<span class="FileUploaderAttachment__image">
<img src="http://placekitten.com/200/300" alt="" />
</span>
```

Full example:

```html
<li class="FileUploaderAttachment">
<!-- Preview image: start -->
<span class="FileUploaderAttachment__image">
<img src="http://placekitten.com/200/300" alt="" />
</span>
<!-- Preview image: end -->
<span class="FileUploaderAttachment__name">
<span class="text-truncate">My resume.docx</span>
</span>
<button type="button" class="FileUploaderAttachment__action">
<span class="accessibility-hidden">Remove</span>
<svg width="24" height="24" aria-hidden="true">
<use xlink:href="/icons/svg/sprite.svg#close" />
</svg>
</button>
</li>
```

### Custom Actions Slot

You can add custom actions to the FileUploaderAttachment.

```html
<span class="FileUploaderAttachment__slot">
<!-- Custom action: start -->
<button type="button" class="FileUploaderAttachment__action">
<span class="accessibility-hidden">Edit</span>
<svg width="24" height="24" aria-hidden="true">
<use xlink:href="/icons/svg/sprite.svg#edit" />
</svg>
</button>
<!-- Custom action: end -->
</span>
```

Full example:

```html
<li class="FileUploaderAttachment">
<svg width="24" height="24" aria-hidden="true">
<use xlink:href="/icons/svg/sprite.svg#file" />
</svg>
<span class="FileUploaderAttachment__name">
<span class="text-truncate">My resume.docx</span>
</span>
<span class="FileUploaderAttachment__slot">
<!-- Custom action: start -->
<button type="button" class="FileUploaderAttachment__action">
<span class="accessibility-hidden">Edit</span>
<svg width="24" height="24" aria-hidden="true">
<use xlink:href="/icons/svg/sprite.svg#edit" />
</svg>
</button>
<!-- Custom action: end -->
</span>
<button type="button" class="FileUploaderAttachment__action">
<span class="accessibility-hidden">Remove</span>
<svg width="24" height="24" aria-hidden="true">
<use xlink:href="/icons/svg/sprite.svg#close" />
</svg>
</button>
</li>
```

#### Attaching Functionality

As long as the FileUploaderAttachment lives inside the `<template>` tag, no functionality can be attached to it.

👉 Don't use IDs to attach functionality to custom actions. IDs must be unique, and the FileUploaderAttachment template
is used for every attachment.

To attach functionality, you need to do so after the `queuedFile.fileUploader` event has been fired:

```js
const editHandler = (event) => {
alert('Custom action clicked');
};

document.addEventListener('queuedFile.fileUploader', () => {
document.querySelectorAll('[data-element="example-action"]').forEach((element) => {
element.removeEventListener('click', editHandler); // Prevent multiple event listeners
element.addEventListener('click', editHandler);
});
});
```

Don't forget to remove the event listener when the FileUploaderAttachment is removed from the DOM:

```js
let filesQueueCounter = 0;

const editHandler = (event) => {
alert('Edit button clicked');
};

document.addEventListener('queuedFile.fileUploader', () => {
filesQueueCounter++;
document.querySelectorAll('[data-element="example-action"]').forEach((element) => {
element.removeEventListener('click', editHandler); // Prevent multiple event listeners
element.addEventListener('click', editHandler);
});
});

document.addEventListener('unqueueFile.fileUploader', () => {
filesQueueCounter--;
if (filesQueueCounter === 0) {
document.querySelectorAll('[data-element="example-action"]').forEach((element) => {
element.removeEventListener('click', editHandler);
});
}
});
```

👉 Read more about [fileUploader JavaScript events](#javascript-events).

## Composition

This is how all subcomponents build up the complete FileUploader:
Expand All @@ -335,8 +470,10 @@ This is how all subcomponents build up the complete FileUploader:
<svg width="24" height="24" aria-hidden="true">
<use xlink:href="/icons/svg/sprite.svg#file" />
</svg>
<span class="text-truncate" data-spirit-populate-field="name">File name</span>
<button type="button" class="FileUploaderAttachment__remove" data-spirit-populate-field="button">
<span class="FileUploaderAttachment__name">
<span class="text-truncate" data-spirit-populate-field="name">File name</span>
</span>
<button type="button" class="FileUploaderAttachment__action" data-spirit-populate-field="button">
<span class="accessibility-hidden">Remove</span>
<svg width="24" height="24" aria-hidden="true">
<use xlink:href="/icons/svg/sprite.svg#close" />
Expand Down Expand Up @@ -372,20 +509,22 @@ This is how all subcomponents build up the complete FileUploader:
<!-- FileUploaderList: start -->
<h3 id="attachments" hidden>Attachments</h3>
<ul class="FileUploaderList" aria-labelledby="attachments" data-spirit-element="list">
<!-- FileUploaderAttachment: start -->
<!-- FileUploaderAttachment INSERTED BY THE JS PLUGIN: start -->
<li class="FileUploaderAttachment">
<svg width="24" height="24" aria-hidden="true">
<use xlink:href="/icons/svg/sprite.svg#file" />
</svg>
<span class="text-truncate">My resume.docx</span>
<button type="button" class="FileUploaderAttachment__remove">
<span class="FileUploaderAttachment__name">
<span class="text-truncate">My resume.docx</span>
</span>
<button type="button" class="FileUploaderAttachment__action">
<span class="accessibility-hidden">Remove</span>
<svg width="24" height="24" aria-hidden="true">
<use xlink:href="/icons/svg/sprite.svg#close" />
</svg>
</button>
</li>
<!-- FileUploaderAttachment: end -->
<!-- FileUploaderAttachment INSERTED BY THE JS PLUGIN: end -->
</ul>
<!-- FileUploaderList: end -->
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@
.FileUploaderAttachment {
@include typography.generate(theme.$attachment-typography);

display: grid;
grid-template-columns: auto 1fr auto;
display: flex;
column-gap: theme.$attachment-column-gap;
align-items: center;
padding: theme.$attachment-padding;
Expand All @@ -18,9 +17,36 @@
background-color: theme.$attachment-background;
}

.FileUploaderAttachment__remove {
.FileUploaderAttachment__image {
width: 56px;
height: 56px;
overflow: hidden;
border: theme.$attachment-image-border;
border-radius: theme.$attachment-image-border-radius;
}

.FileUploaderAttachment__image > img {
width: 100%;
height: 100%;
object-fit: cover;
object-position: center;
}

.FileUploaderAttachment__name {
display: grid;
flex: 1;
}

.FileUploaderAttachment__slot {
display: flex;
gap: theme.$attachment-column-gap;
align-items: center;
justify-content: space-between;
}

.FileUploaderAttachment__action {
@include reset.button();
@include accessibility.min-tap-target($size: theme.$attachment-remove-button-size);
@include accessibility.min-tap-target($size: theme.$attachment-button-size);

color: inherit;

Expand Down
Loading

0 comments on commit 768906f

Please sign in to comment.