-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add prefab file list with dropzone
- Loading branch information
Showing
16 changed files
with
557 additions
and
10 deletions.
There are no files selected for viewing
22 changes: 22 additions & 0 deletions
22
doc-app/app/controllers/docs/ember-input-validation/prefabs/file-list.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import Controller from '@ember/controller'; | ||
import { action } from '@ember/object'; | ||
import { ImmerChangeset } from 'ember-immer-changeset'; | ||
import type { Owner } from '@ember/test-helpers/build-owner'; | ||
|
||
export default class DocsEmberInputValidationPrefabsFileListController extends Controller { | ||
changeset = new ImmerChangeset({ | ||
files: [new File([], 'file.txt')], | ||
disabled: [new File([], 'file.txt')], | ||
error: '', | ||
}); | ||
|
||
constructor(owner: Owner) { | ||
super(owner); | ||
this.changeset.addError({ | ||
message: 'This is an error message', | ||
value: '', | ||
originalValue: '', | ||
key: 'error', | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,5 +20,4 @@ export default class DocsEmberInputValidationPrefabsFileController extends Contr | |
key: 'error', | ||
}); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
43 changes: 43 additions & 0 deletions
43
doc-app/app/templates/docs/ember-input-validation/prefabs/file-list.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
# Input File | ||
|
||
This is an input with a dropzone that allows to upload multiple files. You can also find a list of uploaded files and dowload/delete theme. | ||
|
||
<DocsDemo as |demo|> | ||
<demo.example @name="prefab-tpk-file.hbs"> | ||
<Prefabs::TpkValidationFileList | ||
@label="File" | ||
@changeset={{this.changeset}} | ||
@validationField="files" | ||
@placeholder="Glisser-déposer un fichier ou cliquer pour sélectionner un fichier (max 10Mo)" | ||
/> | ||
<Prefabs::TpkValidationFileList | ||
@label="Disabled" | ||
@changeset={{this.changeset}} | ||
@validationField="disabled" | ||
@placeholder="Glisser-déposer un fichier ou cliquer pour sélectionner un fichier (max 10Mo)" | ||
@disabled=true | ||
/> | ||
<Prefabs::TpkValidationFileList | ||
@label="Error" | ||
@changeset={{this.changeset}} | ||
@validationField="error" | ||
@placeholder="Glisser-déposer un fichier ou cliquer pour sélectionner un fichier (max 10Mo)" | ||
@mandatory=true | ||
/> | ||
</demo.example> | ||
<demo.snippet @name="prefab-tpk-file.hbs"/> | ||
</DocsDemo> | ||
|
||
## Mandatory properties | ||
|
||
- `@validationField`: The field name in the changeset for validation. | ||
- `@changeset`: The changeset object for form validation. | ||
|
||
## Optional properties | ||
|
||
- `@label`: The label for the input field. | ||
- `@disabled`: Whether the input field is disabled. | ||
- `@mandatory`: Whether the input file multiple field is mandatory. | ||
- `@onChange`: The action to be called when the selection changes. | ||
- `@disableDownload`: Whether the download button is disabled. | ||
- `@placeholder`: The placeholder for the dropzone area. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
141 changes: 141 additions & 0 deletions
141
...s/integration/components/ember-input-validation/prefabs/tpk-validation-file-list-test.gts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
import { module, test } from 'qunit'; | ||
import { setupRenderingTest } from 'ember-qunit'; | ||
import { render, triggerEvent } from '@ember/test-helpers'; | ||
import { ImmerChangeset } from 'ember-immer-changeset'; | ||
import { setupIntl } from 'ember-intl/test-support'; | ||
import TpkValidationFileList from '@triptyk/ember-input-validation/components/prefabs/tpk-validation-file-list'; | ||
import { click } from '@ember/test-helpers'; | ||
import { assertTpkCssClassesExist } from '../generic-test-functions/assert-tpk-css-classes-exist'; | ||
import { a11yAudit } from 'ember-a11y-testing/test-support'; | ||
import { settled } from '@ember/test-helpers'; | ||
|
||
|
||
module( | ||
'Integration | Component | Prefabs | tpk-validation-file-list', | ||
function (hooks) { | ||
setupRenderingTest(hooks); | ||
setupIntl(hooks, 'fr-fr'); | ||
|
||
function setupChangeset({ | ||
files = [], | ||
}: { | ||
files: File[] | ||
}) { | ||
return new ImmerChangeset<{ | ||
files: File[]; | ||
}>({ | ||
files, | ||
}); | ||
} | ||
|
||
async function renderComponent(params: { changeset: ImmerChangeset; disabled?: boolean; disableDownload?: boolean; }) { | ||
await render( | ||
<template> | ||
<TpkValidationFileList | ||
@label="label" | ||
@changeset={{params.changeset}} | ||
@validationField="files" | ||
@disableDownload={{params.disableDownload}} | ||
@disabled={{params.disabled}} | ||
@placeholder="Glisser-déposer des fichiers images (max 2mb)" | ||
/> | ||
</template>, | ||
); | ||
} | ||
|
||
|
||
test('Should show download and delete buttons by default when there are files', async function (assert) { | ||
const changeset = setupChangeset({ | ||
files: [new File(['Ember Rules!'], 'file.txt')] | ||
}); | ||
await renderComponent({changeset}); | ||
assert.dom('.tpk-file-list-list-item-action-download').exists(); | ||
assert.dom('.tpk-file-list-list-item-action-delete').exists(); | ||
}); | ||
|
||
test('Should hide download and delete buttons when disableDownload is true and disabled', async function (assert) { | ||
const changeset = setupChangeset({ | ||
files: [new File(['Ember Rules!'], 'file.txt')] | ||
}); | ||
await renderComponent({changeset, disabled: true, disableDownload: true}); | ||
assert.dom('.tpk-file-list-list-item-action-download').doesNotExist(); | ||
assert.dom('.tpk-file-list-list-item-action-delete').doesNotExist(); | ||
}); | ||
|
||
test('Drag and drop files should add them to the changeset and show them in the list', async function (assert) { | ||
const changeset = setupChangeset({ | ||
files: [] | ||
}); | ||
await renderComponent({ changeset }); | ||
await triggerEvent('.tpk-file-list-placeholder-container', 'drop', { | ||
dataTransfer: { | ||
files: [new File(['Ember Rules!'], 'file.txt'), new File(['Ember Rules!'], 'loempia.txt')], | ||
} | ||
}); | ||
assert.dom('.tpk-file-list-list-item').exists({ count: 2 }); | ||
assert.strictEqual(changeset.get('files').length, 2); | ||
}); | ||
|
||
test('Drop a file with a default file in changeset should add the file to the changeset and not remove the default file', async function (assert) { | ||
const changeset = setupChangeset({ | ||
files: [new File(['Ember Rules!'], 'file.txt')] | ||
}); | ||
await renderComponent({ changeset }); | ||
await triggerEvent('.tpk-file-list-placeholder-container', 'drop', { | ||
dataTransfer: { | ||
files: [new File(['Ember Rules!'], 'file.txt')], | ||
} | ||
}); | ||
assert.dom('.tpk-file-list-list-item').exists({ count: 2 }); | ||
assert.strictEqual(changeset.get('files').length, 2); | ||
}); | ||
|
||
test('Delete button should remove the file from the changeset', async function (assert) { | ||
const changeset = setupChangeset({ | ||
files: [new File(['Ember Rules!'], 'file.txt')] | ||
}); | ||
await renderComponent({ changeset }); | ||
await click('.tpk-file-list-list-item:first-child .tpk-file-list-list-item-action-delete'); | ||
assert.dom('.tpk-file-list-list-item').doesNotExist(); | ||
assert.strictEqual(changeset.get('files').length, 0); | ||
}); | ||
|
||
test('It changes data-has-error attribue on error', async function (assert) { | ||
const changeset = setupChangeset({ | ||
files: [] | ||
}); | ||
await renderComponent({changeset}); | ||
|
||
changeset.addError({ | ||
message: 'required', | ||
value: '', | ||
originalValue: '', | ||
key: 'files', | ||
}); | ||
|
||
await settled(); | ||
assert.dom(`[data-test-tpk-file-list-input]`).hasNoText(); | ||
|
||
assert | ||
.dom(`[data-test-tpk-prefab-file-list-container]`) | ||
.hasAttribute('data-has-error', 'true'); | ||
}); | ||
|
||
test('CSS classes exist and have been attached to the correct element', async function (assert) { | ||
const changeset = setupChangeset({ | ||
files: [] | ||
}); | ||
await renderComponent({changeset}); | ||
await assertTpkCssClassesExist(assert,'file-list'); | ||
}); | ||
|
||
test('Accessibility', async function (assert) { | ||
assert.expect(0); | ||
const changeset = setupChangeset({ | ||
files: [] | ||
}); | ||
await renderComponent({changeset}); | ||
await a11yAudit(); | ||
}); | ||
}, | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
86 changes: 86 additions & 0 deletions
86
packages/ember-input-validation/src/components/prefabs/styles/tpk-file-list.css
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
.tpk-file-list-container { | ||
@apply relative flex flex-col w-full pb-4; | ||
} | ||
|
||
.tpk-file-list-container .tpk-label { | ||
@apply label; | ||
} | ||
|
||
.tpk-file-list-input { | ||
@apply hidden; | ||
} | ||
|
||
.tpk-file-list-placeholder-container { | ||
@apply min-h-[180px] w-full border-2 border-dashed border-base-300 rounded-lg flex flex-col items-center justify-center cursor-pointer transition-colors duration-200 hover:border-neutral-content hover:bg-base-200/10; | ||
} | ||
|
||
.tpk-file-list-placeholder-icon { | ||
@apply w-8 h-8 mb-2 opacity-60; | ||
} | ||
|
||
.tpk-file-list-placeholder-container.disabled { | ||
@apply hidden; | ||
} | ||
|
||
.tpk-file-list-placeholder { | ||
@apply text-base-content/60 text-sm text-center; | ||
} | ||
|
||
.tpk-file-list-container[data-has-error~='true'] | ||
.tpk-file-list-placeholder-container { | ||
@apply border-error bg-error/5; | ||
} | ||
|
||
.tpk-file-list-container[data-has-error~='true'] .tpk-label { | ||
@apply text-error; | ||
} | ||
|
||
.tpk-file-list-container[data-has-error~='true'] .tpk-file-list-placeholder { | ||
@apply text-error/60; | ||
} | ||
|
||
.tpk-file-list-container[data-has-error~='true'] .tpk-validation-errors { | ||
@apply text-error text-sm absolute right-0 -bottom-1; | ||
} | ||
|
||
/* File list */ | ||
|
||
.tpk-file-list-list { | ||
@apply space-y-4 mt-4; | ||
} | ||
|
||
.tpk-file-list-list.disabled { | ||
@apply mt-0; | ||
} | ||
|
||
.tpk-file-list-list-item { | ||
@apply flex items-center space-x-6 px-4 py-2 border border-base-300 rounded; | ||
} | ||
|
||
.tpk-file-list-list-item-preview { | ||
@apply w-7 h-7 flex-shrink-0; | ||
} | ||
|
||
.tpk-file-list-list-item-preview img { | ||
@apply w-7 h-7 object-cover rounded object-center; | ||
} | ||
|
||
.tpk-file-list-list-item-content { | ||
@apply flex flex-col flex-grow truncate text-ellipsis; | ||
} | ||
|
||
.tpk-file-list-list-item-content-name { | ||
@apply text-sm font-semibold truncate text-ellipsis; | ||
} | ||
|
||
.tpk-file-list-list-item-content-size { | ||
@apply text-xs text-base-content/60; | ||
} | ||
|
||
.tpk-file-list-list-item-action { | ||
@apply flex gap-2 flex-shrink-0; | ||
} | ||
|
||
.tpk-file-list-list-item-action button, .tpk-file-list-list-item-action img { | ||
@apply w-6 h-6; | ||
} |
Oops, something went wrong.