diff --git a/components/molecule/autosuggest/src/components/MultipleSelection/index.js b/components/molecule/autosuggest/src/components/MultipleSelection/index.js index 2f7ce852e8..cdb0930b2d 100644 --- a/components/molecule/autosuggest/src/components/MultipleSelection/index.js +++ b/components/molecule/autosuggest/src/components/MultipleSelection/index.js @@ -105,7 +105,7 @@ const MoleculeAutosuggestFieldMultiSelection = ({ innerRefInput={moleculeInputRef} inputMode={inputMode} isOpen={isOpen} - isVisibleClear={!disabled && tags.length} + isVisibleClear={!disabled && tags.length>0} noBorder onChange={handleChange} onChangeTags={handleChangeTags} diff --git a/components/molecule/autosuggest/src/components/SingleSelection/index.js b/components/molecule/autosuggest/src/components/SingleSelection/index.js index edbd90fe86..5b60462188 100644 --- a/components/molecule/autosuggest/src/components/SingleSelection/index.js +++ b/components/molecule/autosuggest/src/components/SingleSelection/index.js @@ -73,7 +73,7 @@ const MoleculeAutosuggestSingleSelection = ({ id={id} reference={refInput} inputMode={inputMode} - isVisibleClear={value} + isVisibleClear={!!value} leftIcon={leftIcon} maxLength={maxLength} minLength={minLength} diff --git a/components/molecule/fileUploader/.gitignore b/components/molecule/fileUploader/.gitignore new file mode 100644 index 0000000000..a9f4ed5456 --- /dev/null +++ b/components/molecule/fileUploader/.gitignore @@ -0,0 +1,2 @@ +lib +node_modules \ No newline at end of file diff --git a/components/molecule/fileUploader/.npmignore b/components/molecule/fileUploader/.npmignore new file mode 100644 index 0000000000..83de8b2bf3 --- /dev/null +++ b/components/molecule/fileUploader/.npmignore @@ -0,0 +1,5 @@ +assets +demo +src +test +CHANGELOG.md \ No newline at end of file diff --git a/components/molecule/fileUploader/CHANGELOG.md b/components/molecule/fileUploader/CHANGELOG.md new file mode 100644 index 0000000000..140bc68166 --- /dev/null +++ b/components/molecule/fileUploader/CHANGELOG.md @@ -0,0 +1,527 @@ +# CHANGELOG + +# 2.21.0 (2022-07-11) + + +### Features + +* **components/molecule/photoUploader:** add photo uploader max callback ([77f540d](https://github.com/SUI-Components/sui-components/commit/77f540dbe19ac99f25fb7a2aeadd46e48b74ba56)) + + + +# 2.20.0 (2022-06-23) + + +### Features + +* **components/molecule/photoUploader:** Avoid publishing huge CHANGELOG.md ([03c82db](https://github.com/SUI-Components/sui-components/commit/03c82dba9709b4bbb4f1bbe690da9040268a3a65)) + + + +# 2.19.0 (2022-06-17) + + +### Features + +* **components/molecule/photoUploader:** add two func props: onDrop and onFileDialogOpen ([90efe9b](https://github.com/SUI-Components/sui-components/commit/90efe9b296c44197a34ed040d84b8ba02ff92b46)) + + + +# 2.18.0 (2022-06-15) + + +### Features + +* **components/molecule/photoUploader:** add padding to photo uploader ([23d0dbb](https://github.com/SUI-Components/sui-components/commit/23d0dbb57881270bc6c9128f1cd19289fe0412fc)) + + + +# 2.17.0 (2022-05-24) + + +### Features + +* **components/molecule/photoUploader:** optional divider ([37069c5](https://github.com/SUI-Components/sui-components/commit/37069c504685d82ccb5f9cee935247ecf11f74cf)) + + + +# 2.16.0 (2022-05-06) + + +### Features + +* **components/molecule/photoUploader:** center text when text dont fit on container ([f0ab9c3](https://github.com/SUI-Components/sui-components/commit/f0ab9c3b02dfb8df48f71b8ec0e9311fb3a5b446)) +* **components/molecule/photoUploader:** make mininum height a default scss var to modify its value ([d4101af](https://github.com/SUI-Components/sui-components/commit/d4101afd0d3bbc7c03c4b738abe75eaa869ba921)) + + + +# 2.15.0 (2022-05-04) + + +### Features + +* **components/molecule/photoUploader:** add overflow hidden to make visible the defined border-radi ([651f3c7](https://github.com/SUI-Components/sui-components/commit/651f3c73dd9c8142cbf80d643d54b19cb635f7a7)) +* **components/molecule/photoUploader:** fix border-radius avoiding the use of overflow hidden ([ec030b8](https://github.com/SUI-Components/sui-components/commit/ec030b846e16208d94e0788692dfa55cfb326688)) + + + +# 2.14.0 (2022-04-13) + + +### Bug Fixes + +* **components/molecule/photoUploader:** Fix release version ([e1218c5](https://github.com/SUI-Components/sui-components/commit/e1218c58c0299d712fc77a795afe6ca33cde10e4)) +* **components/molecule/photoUploader:** JSX Content ([d6bb641](https://github.com/SUI-Components/sui-components/commit/d6bb64116012e206ef41d0a3d9ee2872813ba9e0)) +* **components/molecule/photoUploader:** maintain the status managing ([bf3b250](https://github.com/SUI-Components/sui-components/commit/bf3b250b435e0d7bfadb24866ae1582543da9980)) + + +### Features + +* **components/molecule/photoUploader:** add content feature on molecule photoUploader component ([29421e9](https://github.com/SUI-Components/sui-components/commit/29421e92b84ac9bd248a46e49680a3ec533baa12)) +* **components/molecule/photoUploader:** apply feedback ([a066e0f](https://github.com/SUI-Components/sui-components/commit/a066e0fd6d760d4df802e38a7feb56bc8029e66b)) +* **components/molecule/photoUploader:** apply feedback ([433f9e4](https://github.com/SUI-Components/sui-components/commit/433f9e464fac3650d76eb9acad008548652e3392)) +* **components/molecule/photoUploader:** Force new release of the pkg ([0d977b0](https://github.com/SUI-Components/sui-components/commit/0d977b0813d2f98ae4ca655fe255e46cb90d58cf)) +* **components/molecule/photoUploader:** update component ([afae83e](https://github.com/SUI-Components/sui-components/commit/afae83e8e7bef4bd731bb78d4de6b3d66c418eef)) + + + +# 2.11.0 (2022-04-05) + + +### Bug Fixes + +* **components/molecule/photoUploader:** resolve linting errors ([c981bb9](https://github.com/SUI-Components/sui-components/commit/c981bb93a845392b4dea720aa9ecd5e4177931e2)) + + + +# 2.10.0 (2022-01-21) + + +### Bug Fixes + +* **components/molecule/photoUploader:** Add missing dependency when using legacy-peer-deps ([6c6c67c](https://github.com/SUI-Components/sui-components/commit/6c6c67cc78dbe1a874d41819c47eee07c25bae57)) + + + +# 2.9.0 (2022-01-20) + + +### Features + +* **components/molecule/photoUploader:** update react-dropzone and react-sortablejs ([452fda7](https://github.com/SUI-Components/sui-components/commit/452fda7f48a9a7cf6f013238ddbf4828f4b7123e)) + + + +# 2.8.0 (2022-01-18) + + +### Features + +* **components/molecule/photoUploader:** add new prop to modify button shape on initial state ([6b00a94](https://github.com/SUI-Components/sui-components/commit/6b00a949fbe4550316f2ce316353fd7e23225e98)) +* **components/molecule/photoUploader:** remove default prop value ([c784bc4](https://github.com/SUI-Components/sui-components/commit/c784bc426ed78278612a3e075d44bf074df50c08)) + + + +# 2.7.0 (2021-12-23) + + +### Bug Fixes + +* **components/molecule/photoUploader:** Add condition to prepareFiles to know when callbackUploadPho ([9a3e964](https://github.com/SUI-Components/sui-components/commit/9a3e9644656213b37550a7781c5d9e7b21e5b23b)) +* **components/molecule/photoUploader:** Change condition to show error on upload image endpoint erro ([2aa2bb8](https://github.com/SUI-Components/sui-components/commit/2aa2bb8ba6d75dfa7ba2e13effa290c82a9a0244)) + + + +# 2.6.0 (2021-12-20) + + +### Features + +* **components/molecule/photoUploader:** Add errorSaveImageEndpoint prop ([ea87331](https://github.com/SUI-Components/sui-components/commit/ea87331a1cafccbe0d685cafc76b68c9aa455a19)) +* **components/molecule/photoUploader:** Add url control in prepareFile function ([4d4d711](https://github.com/SUI-Components/sui-components/commit/4d4d71102a5e01bd3ec29019f75ddd8a4136782e)) +* **components/molecule/photoUploader:** Remove required from errorSaveImageEndpoint prop ([70c578c](https://github.com/SUI-Components/sui-components/commit/70c578c74d7cf306ec2c11acfd5a8459483d0a24)) + + + +# 2.5.0 (2021-07-30) + + +### Features + +* **components/molecule/photoUploader:** Add new bg token for add new photo button ([d8c9a7d](https://github.com/SUI-Components/sui-components/commit/d8c9a7d2edecc6ab90b84c1b4696e8d4a27aea1e)) + + + +# 2.4.0 (2021-07-23) + + +### Features + +* **components/molecule/photoUploader:** add actions enum in config ([7c0a420](https://github.com/SUI-Components/sui-components/commit/7c0a4201c9c8f4809bcb0bddcc83dcf8753c7b1b)) +* **components/molecule/photoUploader:** instead of name the param, get the rest and pass it to the ([1a77d44](https://github.com/SUI-Components/sui-components/commit/1a77d44b4e6bf917fe286d094a0440a580945947)) +* **components/molecule/photoUploader:** on callbackPhotosUploaded pass data object with which actio ([8cae650](https://github.com/SUI-Components/sui-components/commit/8cae6504c5de286bf98bbbfff7251dae482c9e57)) +* **components/molecule/photoUploader:** onEnd callback rename incoming sortedFile param into event ([1f94b8d](https://github.com/SUI-Components/sui-components/commit/1f94b8d237e680d97eacf5e923593dc1fe9d73f0)) +* **components/molecule/photoUploader:** rename LOAD_INITIAL_PHOTOS action to INITIAL_LOAD ([be0dde1](https://github.com/SUI-Components/sui-components/commit/be0dde1af8409e093c159e2f8b8590821d46deac)) + + + +# 2.3.0 (2021-07-02) + + +### Features + +* **components/molecule/photoUploader:** add tokens ([fae4f3b](https://github.com/SUI-Components/sui-components/commit/fae4f3bd04a156973381aa40d37190742fe3de3a)) + + + +# 2.2.0 (2021-07-02) + + +### Features + +* **components/molecule/photoUploader:** add tokens ([c5ab832](https://github.com/SUI-Components/sui-components/commit/c5ab8322ceb1684b7d84325a4a33a723dcf288f0)) + + + +# 1.1.0 (2021-07-01) + + +### Bug Fixes + +* **components/molecule/photoUploader/demo:** fix demo ([5f0c787](https://github.com/SUI-Components/sui-components/commit/5f0c787fc5d15b39e17e4080b088c6faa19d4be4)) + + + +# 2.1.0 (2021-06-22) + + +### Features + +* **components/molecule/photoUploader:** Avoid using slash ([4f99ea9](https://github.com/SUI-Components/sui-components/commit/4f99ea9d8e4f9ce27655d68b34730a819c965134)) + + + +# 2.0.0 (2021-06-14) + + +### Features + +* **components/molecule/photoUploader:** fix forgotten url in formatToBase64 and follow contract on ([843ec93](https://github.com/SUI-Components/sui-components/commit/843ec932dd632a9335ebafea439da13ee3b37491)) +* **components/molecule/photoUploader:** restore the way how is returning newFiles ([a9d974b](https://github.com/SUI-Components/sui-components/commit/a9d974b16cfd2aece0410b9434b423cd22eba208)) +* **components/molecule/photoUploader:** treat initialPhotos as an object and extract it an id ([7eccaad](https://github.com/SUI-Components/sui-components/commit/7eccaad5e3d101e615800a034b3b1b682caed8ae)) + + + +# 1.28.0 (2021-06-03) + + +### Bug Fixes + +* **components/molecule/photoUploader:** sui-theme package directory ([ee43280](https://github.com/SUI-Components/sui-components/commit/ee4328083c961d578b82507b94b18a846e163526)) +* **Root:** hotfix for enabling the ci process ([9c06c92](https://github.com/SUI-Components/sui-components/commit/9c06c92da63147017caa16ff3e1d139f4b42b35d)) + + + +# 1.27.0 (2021-05-04) + + +### Features + +* **molecule/photoUploader:** allow use forwarded ref and merge with the useDropzone ref ([1e6e31b](https://github.com/SUI-Components/sui-components/commit/1e6e31b860b714c01ec3603c82b2363ee8888cde)) + + + +# 1.26.0 (2021-04-29) + + +### Bug Fixes + +* **molecule/photoUploader:** revert ([6f8859c](https://github.com/SUI-Components/sui-components/commit/6f8859c5a955baf94e732e2f3f3adbb21ddf0b67)) + + + +# 1.25.0 (2021-04-29) + + +### Features + +* **molecule/photoUploader:** implement ref forwarding ([b9e8127](https://github.com/SUI-Components/sui-components/commit/b9e81277bf198073590eeeb52383509c969b2d62)) + + + +# 1.24.0 (2021-04-26) + + +### Features + +* **molecule/photoUploader:** add border for dropzone mobile ([67b34fc](https://github.com/SUI-Components/sui-components/commit/67b34fc2b415737499db161b78821a45e4dcb32b)) + + + +# 1.23.0 (2021-02-10) + + +### Features + +* **molecule/photoUploader:** add border for dropzone when is empty different ([cccd43a](https://github.com/SUI-Components/sui-components/commit/cccd43aff30a14374c3dc7842794ae3bbd3edb59)) + + + +# 1.22.0 (2021-01-05) + + +### Bug Fixes + +* **molecule/photoUploader:** proptype ([d3cda3c](https://github.com/SUI-Components/sui-components/commit/d3cda3cc84a8da49fb3214dfded5a44e488d6897)) +* **molecule/photoUploader:** proptypes and tests ([631a43d](https://github.com/SUI-Components/sui-components/commit/631a43d42b629c1d81df2d6d34e2e2d487bd1bd4)) + + + +# 1.21.0 (2020-11-30) + + +### Features + +* **molecule/photoUploader:** add scss variables ([568dafa](https://github.com/SUI-Components/sui-components/commit/568dafa5db662a01f6dae6b8d97bb82bc6294d18)) + + + +# 1.20.0 (2020-11-24) + + +### Features + +* **molecule/photoUploader:** add background color variable in the intitial state ([ce4ea8a](https://github.com/SUI-Components/sui-components/commit/ce4ea8a2394ed661e817eb5c673b3e03ac319100)) +* **molecule/photoUploader:** add border variable to photo uploader ([138fdb8](https://github.com/SUI-Components/sui-components/commit/138fdb8024e17e00a4249861bbb8368a7bd817ed)) + + + +# 1.19.0 (2020-11-24) + + +### Bug Fixes + +* **Root:** fix lint errors ([bc894a7](https://github.com/SUI-Components/sui-components/commit/bc894a7106b36e61c5c96355b1992e6703c31cce)) + + +### Features + +* **molecule/photoUploader:** Use new jsx runtime ([fe4997b](https://github.com/SUI-Components/sui-components/commit/fe4997b3c195e8b19f37185c97c7058a6864b096)) + + + +# 1.18.0 (2020-10-27) + + +### Bug Fixes + +* **molecule/photoUploader:** comment issue redirection ([5e16429](https://github.com/SUI-Components/sui-components/commit/5e164299deb2f2034d186e1f03789c4da811b512)) +* **molecule/photoUploader:** rollback usage of fixed version as new version has been released with t ([86736b9](https://github.com/SUI-Components/sui-components/commit/86736b9ab7fff4136770ab30514a69011c099e0e)) + + + +# 1.17.0 (2020-10-23) + + +### Bug Fixes + +* **molecule/photoUploader:** install fixed version of file-selector to avoid problems to verticals ([d9fb2c4](https://github.com/SUI-Components/sui-components/commit/d9fb2c41f6905dfced81107c77d651419f066af9)) + + + +# 1.16.0 (2020-07-21) + + +### Bug Fixes + +* **molecule/photoUploader:** fix missing default values making tests to fail ([f5802ee](https://github.com/SUI-Components/sui-components/commit/f5802eede1d15f2227784d9b3715135dd87a21c9)) + + + +# 1.15.0 (2020-06-17) + + +### Features + +* **molecule/photoUploader:** fix to avoid rotation based on exif, if browser has this feature by de ([91ae59d](https://github.com/SUI-Components/sui-components/commit/91ae59d64cdf9f14c4eb2186eaca0c5645673fbe)) + + + +# 1.14.0 (2020-06-08) + + +### Features + +* **molecule/photoUploader:** add callback to uploadPhoto when image is modified ([a6246fb](https://github.com/SUI-Components/sui-components/commit/a6246fbd6f82c4053b3e99064b628c1697c8949f)) +* **molecule/photoUploader:** add upload Callback ([416cb5c](https://github.com/SUI-Components/sui-components/commit/416cb5ccb09ead225e01ebc885955c11aca8bdbb)) +* **molecule/photoUploader:** fix a typo ([529e331](https://github.com/SUI-Components/sui-components/commit/529e3312cc08f66e10a752f848f394ad0aafad16)) + + + +# 1.13.0 (2020-06-02) + + +### Features + +* **molecule/photoUploader:** fix NotRepeatedFilter ([59a6359](https://github.com/SUI-Components/sui-components/commit/59a6359753225a1bcc11c7cfad6640d85339cdbb)) + + + +# 1.12.0 (2020-05-29) + + +### Features + +* **molecule/photoUploader:** add assets folder to .npmignore ([c26ad89](https://github.com/SUI-Components/sui-components/commit/c26ad89dd06783092efd8e901e4e4e673d759d44)) + + + +# 1.11.0 (2020-05-21) + + +### Features + +* **molecule/photoUploader:** add preview to be returned on callback, also fix callback when all ima ([8605961](https://github.com/SUI-Components/sui-components/commit/86059613333d2c9f8e0f1677bfde5ff2865b194b)) +* **molecule/photoUploader:** rename and refactor ([a149337](https://github.com/SUI-Components/sui-components/commit/a1493370142615bc79253ff4ec3b4ae24ef47d06)) + + + +# 1.10.0 (2020-05-19) + + +### Features + +* **molecule/photoUploader:** add border-radius variables ([b4b408e](https://github.com/SUI-Components/sui-components/commit/b4b408e793458d5098ffe001a52e82ae4f9591b7)) +* **molecule/photoUploader:** join variables ([372a5fd](https://github.com/SUI-Components/sui-components/commit/372a5fd6ecb48bfa54d2263188a997700e2bf60f)) +* **molecule/photoUploader:** remove unused var ([d676298](https://github.com/SUI-Components/sui-components/commit/d676298743093bf9e3f52c9b45ad91ab82f4e533)) + + + +# 1.9.0 (2020-04-23) + + +### Bug Fixes + +* **molecule/photoUploader:** prevent submit form when photo uploader button is clicked ([21ec7e5](https://github.com/SUI-Components/sui-components/commit/21ec7e5c4f0c3c6e477351cc347ac8cb0c17cbfc)) + + + +# 1.8.0 (2020-04-21) + + +### Features + +* **molecule/photoUploader:** add fileName on returned list of files ([74999b3](https://github.com/SUI-Components/sui-components/commit/74999b303084ea596d5280afe2aadfe9467ed570)), closes [#1097](https://github.com/SUI-Components/sui-components/issues/1097) +* **molecule/photoUploader:** expose file instead of fileName ([64eeba5](https://github.com/SUI-Components/sui-components/commit/64eeba58852451b008b7e25ee80d8658fdd4f7e1)) + + + +# 1.7.0 (2020-04-15) + + +### Features + +* **molecule/photoUploader:** fix counter styles ([6ab5325](https://github.com/SUI-Components/sui-components/commit/6ab5325e423686d10d61260885535d21a6a3615b)) +* **molecule/photoUploader:** fix photouploader: ratio image disabled ([38829c6](https://github.com/SUI-Components/sui-components/commit/38829c6edde5293bd102b10880694c28073c1755)) + + + +# 1.6.0 (2020-04-01) + + +### Features + +* **molecule/photoUploader:** add $bdrs-photo-uploader-initial-state var ([1027157](https://github.com/SUI-Components/sui-components/commit/102715777d124fb86a44f08683db9bc1d9854f7c)) + + + +# 1.5.0 (2020-03-24) + + +### Features + +* **molecule/photoUploader:** add button color prop ([3bf3d8c](https://github.com/SUI-Components/sui-components/commit/3bf3d8c3a7ee2e557863263c7413817336294d42)) +* **molecule/photoUploader:** add button design prop ([f3a56aa](https://github.com/SUI-Components/sui-components/commit/f3a56aae0f4f58a969cc8a31559087cdf120ff9c)) +* **molecule/photoUploader:** add default to var ([67ae3f9](https://github.com/SUI-Components/sui-components/commit/67ae3f9514183e8399d2c96b7c111b10d3e5f250)) +* **molecule/photoUploader:** add default var ([3aefdea](https://github.com/SUI-Components/sui-components/commit/3aefdead154f8b5f1dded72a7e9b054697253f08)) +* **molecule/photoUploader:** add scss var ([7a69683](https://github.com/SUI-Components/sui-components/commit/7a696837b4837dccdcb4a22a0a770276f889ad0a)) +* **molecule/photoUploader:** use buttonColor passed as props ([0638882](https://github.com/SUI-Components/sui-components/commit/06388825f7685cc358ec241337bc9b5e803db8ec)) +* **molecule/photoUploader:** use primary color as defautl ([c0f47b2](https://github.com/SUI-Components/sui-components/commit/c0f47b2be79a62ca4f6b937cb182f95d2dc56711)) + + + +# 1.4.0 (2020-03-11) + + +### Features + +* **molecule/photoUploader:** remove [@schibstedspain](https://github.com/schibstedspain) package ([d3d3b7d](https://github.com/SUI-Components/sui-components/commit/d3d3b7d3298bf6142c61cbcba01484833f445a36)) + + + +# 1.3.0 (2020-03-05) + + +### Bug Fixes + +* **molecule/photoUploader:** add 1px more to style padding ([27ce682](https://github.com/SUI-Components/sui-components/commit/27ce6823d287d0f0fa753b664227519f6374a632)) + + +### Features + +* **molecule/photoUploader:** disable cropping via prop ([6f463c4](https://github.com/SUI-Components/sui-components/commit/6f463c471af0f3609dc8fd5e6e622008e77488a7)) + + + +# 1.2.0 (2020-03-04) + + +### Bug Fixes + +* **molecule/photoUploader:** counter positioning ([588024e](https://github.com/SUI-Components/sui-components/commit/588024e9943f16c1070e18799b9424ed95f2c662)) + + +### Features + +* **molecule/photoUploader:** add pixel ([b3d0ebc](https://github.com/SUI-Components/sui-components/commit/b3d0ebcc4f860ab355d9fdc080e881fbe409e3de)) +* **molecule/photoUploader:** fix rejected files callback ([a32ccd2](https://github.com/SUI-Components/sui-components/commit/a32ccd21de7584f4b60307a65b6e5739111725f0)) +* **molecule/photoUploader:** rename func ([8ea9fd4](https://github.com/SUI-Components/sui-components/commit/8ea9fd4f7a1a4e3855f923f9ad5d66dab93e6daf)) + + + +# 1.1.0 (2020-02-28) + + +### Features + +* **molecule/photoUploader:** ad some variables ([808f55e](https://github.com/SUI-Components/sui-components/commit/808f55eca219d77e9f72928ccd86a6ff5dd2a79b)) +* **molecule/photoUploader:** add color to button, to avoid use deprecated props ([797407b](https://github.com/SUI-Components/sui-components/commit/797407bd93bf24b55e7701e8f9e3416ce77a5864)) +* **molecule/photoUploader:** add initial rotation based on EXIF metadata ([7018d7a](https://github.com/SUI-Components/sui-components/commit/7018d7a6773b50eadeb0f85554fcf5f205a8143e)) +* **molecule/photoUploader:** add new callback: callbackPhotosRejected ([27e94d2](https://github.com/SUI-Components/sui-components/commit/27e94d2023a1619eb548b769bca7a2010129bdd6)) +* **molecule/photoUploader:** add new prop dragDelay ([afeb2e9](https://github.com/SUI-Components/sui-components/commit/afeb2e907f3dc11a4555408cd7e8f5e222ef803f)) +* **molecule/photoUploader:** add prop to allow upload repeated photos (false by default) ([7bc8d8e](https://github.com/SUI-Components/sui-components/commit/7bc8d8e132eb6be2fa21265426290d5f2a561517)) +* **molecule/photoUploader:** add README, and improve proptypes info ([4f56a36](https://github.com/SUI-Components/sui-components/commit/4f56a36a46ed1be94338f34d47bd39996be1453e)) +* **molecule/photoUploader:** add scroll to bottom of the component went error notification appears ([47ef4c6](https://github.com/SUI-Components/sui-components/commit/47ef4c66b5a3ffc0e4a366223c54f62282ac61e7)) +* **molecule/photoUploader:** add token $bd-photo-uploader-thumb-chosen ([d1a573a](https://github.com/SUI-Components/sui-components/commit/d1a573a054d803a1a1ff10b7832024ee06a7fbcc)) +* **molecule/photoUploader:** added rotateDirection prop, it can be 'clockwise' or 'counterclockwise ([cf3016f](https://github.com/SUI-Components/sui-components/commit/cf3016f8b02566f8ccac9f5019bac4d37ae0ee15)) +* **molecule/photoUploader:** create PhotosPreview component and extract its funcs ([7f9fe16](https://github.com/SUI-Components/sui-components/commit/7f9fe1691aaded841dd93a9afb0b5ea85214c2a5)) +* **molecule/photoUploader:** export default values from config to phototools.js ([db11a37](https://github.com/SUI-Components/sui-components/commit/db11a37b7883f0a330675786ffedddfc764a57c3)) +* **molecule/photoUploader:** extract photo actions like loaders and filters ([8142f87](https://github.com/SUI-Components/sui-components/commit/8142f8720d939466d338131184769d87736f1060)) +* **molecule/photoUploader:** fix border radius main counter ([6a2c56d](https://github.com/SUI-Components/sui-components/commit/6a2c56d52686fcc6878d31c970cd057c0d6a4286)) +* **molecule/photoUploader:** fix default variables ([82434a8](https://github.com/SUI-Components/sui-components/commit/82434a83bdb78abe0718fa5532e86f745f72e1b2)) +* **molecule/photoUploader:** fix FileReader lint ([ee9bbde](https://github.com/SUI-Components/sui-components/commit/ee9bbde776890b4d094ff64ab2661582ef898f31)) +* **molecule/photoUploader:** fix FileReader lint (a different one!) ([3fbf322](https://github.com/SUI-Components/sui-components/commit/3fbf322143860a3e628906027e6a01091e38f3a7)) +* **molecule/photoUploader:** fix first rotation action ([8f19e32](https://github.com/SUI-Components/sui-components/commit/8f19e32ff4ad770b93f85e60da97e5cf09c4906a)) +* **molecule/photoUploader:** fix scss use const BASE_CLASS_NAME ([bbc96e0](https://github.com/SUI-Components/sui-components/commit/bbc96e03f16e72c3eb527b25356dd49248f0e655)) +* **molecule/photoUploader:** fix svgs icons ([9276af6](https://github.com/SUI-Components/sui-components/commit/9276af6085b4fad51db92ef917f1eadcf5530f67)) +* **molecule/photoUploader:** improve counter vertical alignment ([9380ab1](https://github.com/SUI-Components/sui-components/commit/9380ab107a8353d3f02e23bb9b71fd5f59b2f426)) +* **molecule/photoUploader:** improve playground and copies used. Also change the default accepted i ([b36f241](https://github.com/SUI-Components/sui-components/commit/b36f2412071618efa37043b17992c48137ff403c)) +* **molecule/photoUploader:** improve README text ([011da10](https://github.com/SUI-Components/sui-components/commit/011da103af68cac53b9dd0913a1fc12d45ae032c)) +* **molecule/photoUploader:** initial commit ⚛ new molecule/photoUploader ([e897a36](https://github.com/SUI-Components/sui-components/commit/e897a36c3e19e0c0a79947b7717090571d0df73b)) +* **molecule/photoUploader:** remove commented func ([94a6c97](https://github.com/SUI-Components/sui-components/commit/94a6c970ade69b4c2a820bb78253ef3621747baa)) +* **molecule/photoUploader:** remove comments ([24fdd47](https://github.com/SUI-Components/sui-components/commit/24fdd472bbaaf6bf31972b96ac8cebab3115f9f4)) +* **molecule/photoUploader:** remove unnecessary dependency from package.json ([176dd47](https://github.com/SUI-Components/sui-components/commit/176dd475f576624fa5405cd6374e789aa722b458)) +* **molecule/photoUploader:** replace useEffect with useMount ([9970a92](https://github.com/SUI-Components/sui-components/commit/9970a9276e86794eb3dbf1e97ba06b1b6b6f1cbd)) + + + diff --git a/components/molecule/fileUploader/README.md b/components/molecule/fileUploader/README.md new file mode 100644 index 0000000000..d98771bd2c --- /dev/null +++ b/components/molecule/fileUploader/README.md @@ -0,0 +1,86 @@ +# MoleculePhotoUploader + +`MoleculePhotoUploader` is a component that lets you drag and drop images on it, or click it to add images. Also, on mobile, let you add photos directly taken with the camera. + +Once uploaded into the component, all images will be resized if they are exceeding the max resolution defined by props and/or cropped to fit a given ratio. And JPEG encoded with a little bit of compression. + +After they are loaded, the images can be sorted, rotated or deleted from the list. + +A set of initial images can be load with an array of URLs passed by props. + +Every modification of the list will return a list of Blobs (jpeg encoded!) to be uploaded on a server or whatever you like, and with the Blob, some useful info: + +> `url` (String) if the image is one of the initially passed by props will contain an url, if it's undefined, it's a new image. + +> `id` (String) you could pass an id to identify each image that was initially passed + +> `isNew` (Boolean) if it's a new uploaded image, will be true, if not, will be false and it will have an `url`. + +> `isModified` (Boolean): if an image of the initialPhotos, has been rotated, will be `isModified: true` + +> `hasErrors` (Boolean) if a initial photo has some kind of error when the component try to download, will have `hasErrors: true` + +> `file` (Object) it's the new uploaded file. + +> `previewUrl` (String) a preview url to use if you wanna preview the images outside the photoUploader component + +## Installation + +```sh +$ npm install @s-ui/react-molecule-photo-uploader --save +``` + +## Usage + +After importing the component `MoleculePhotoUploader` like this + +```js +import MoleculePhotoUploader from '@s-ui/react-molecule-photo-uploader' +``` + +### Basic usage + +```js + console.log(rejectedPhotos)} + callbackPhotosUploaded={acceptedPhotos => console.log(acceptedPhotos)} + callbackUploadPhoto={(file, oldUrl) => console.log(file, oldUrl)} + limitPhotosUploadedText={_limitPhotosUploaded} + limitPhotosUploadedNotification={_limitPhotosUploadedNotification} + mainPhotoLabel={'PRINCIPAL'} + maxPhotos={10} + rotationDirection={'clockwise'} + initialPhotos={[ + {url: 'https://images.net/image1.jpg', id: '6c7ee3d8-97db-4142-8520-5136fccfc40b'}, + {url: 'https://images.net/image2.jpg}' + ]} +/> +``` + +> **Find full description and more examples in the [demo page](#).** diff --git a/components/molecule/fileUploader/demo/articles/DefaultArticle.js b/components/molecule/fileUploader/demo/articles/DefaultArticle.js new file mode 100644 index 0000000000..f3bcb4abc4 --- /dev/null +++ b/components/molecule/fileUploader/demo/articles/DefaultArticle.js @@ -0,0 +1,136 @@ +import PropTypes from 'prop-types' + +import { + Article, + Code, + H2, + ListItem, + Paragraph, + UnorderedList +} from '@s-ui/documentation-library' + +import MoleculePhotoUploader from '../../src/index.js' +import { + _addPhotoTextButton, + _addPhotoTextSkeleton, + _callbackPhotosRejected, + _callbackPhotosUploaded, + _callbackUploadPhoto, + _dragPhotoDividerTextInitialContent, + _dragPhotoTextInitialContent, + _dropPhotosHere, + _errorCorruptedPhotoUploaded, + _errorFileExcededMaxSize, + _errorFormatPhotoUploaded, + _errorInitialPhotoDownloadError, + _limitPhotosUploaded, + _limitPhotosUploadedNotification, + _mainPhotoLabel, + _maxPhotos, + _notificationErrorFormatPhotoUploaded, + _uploadingPhotosText +} from '../config.js' +import { + _addMorePhotosIcon, + _deleteIcon, + _dragPhotosIcon, + _infoIcon, + _rejectPhotosIcon, + _retryErrorPhotosIcon, + _rotateIcon +} from '../icons.js' + +const DefaultArticle = ({className}) => { + return ( +
+

Default

+ + Every modification of the list will return a list of Blobs (jpeg + encoded!) to be uploaded on a server or whatever you like, and with the + Blob, some useful info: + + + Once uploaded into the component, all images will be resized if they are + exceeding the max resolution defined by props and/or cropped to fit a + given ratio. And JPEG encoded with a little bit of compression. + + + {[ + [ + 'url', + 'string', + "if the image is one of the initially passed by props will contain an url, if it's undefined, it's a new image." + ], + [ + 'id', + 'string', + 'you could pass an id to identify each image that was initially passed' + ], + [ + 'isNew', + 'boolean', + "if it's a new uploaded image, will be true, if not, will be false and it will have an `url`." + ], + [ + 'isModified', + 'boolean', + 'if an image of the initialPhotos, has been rotated, will be `isModified: true`' + ], + [ + 'hasErrors', + 'boolean', + 'if a initial photo has some kind of error when the component try to download, will have `hasErrors: true`' + ], + ['file', 'object', "it's the new uploaded file"], + [ + 'previewUrl', + 'string', + 'a preview url to use if you wanna preview the images outside the photoUploader component' + ] + ].map(([key, propType, text]) => ( + + {key} + {propType}: {text} + + ))} + + +
+ ) +} + +DefaultArticle.displayName = 'DefaultArticle' + +DefaultArticle.propTypes = { + className: PropTypes.string +} + +export default DefaultArticle diff --git a/components/molecule/fileUploader/demo/articles/InitialPhotosArticle.js b/components/molecule/fileUploader/demo/articles/InitialPhotosArticle.js new file mode 100644 index 0000000000..1c50341a7c --- /dev/null +++ b/components/molecule/fileUploader/demo/articles/InitialPhotosArticle.js @@ -0,0 +1,112 @@ +import PropTypes from 'prop-types' + +import {Article, H2, Paragraph} from '@s-ui/documentation-library' + +import MoleculePhotoUploader from '../../src/index.js' +import { + _addPhotoTextButton, + _addPhotoTextSkeleton, + _allowUploadDuplicatedPhotos, + _callbackPhotosRejected, + _callbackPhotosUploaded, + _callbackUploadPhoto, + _dragDelay, + _dragPhotoDividerTextInitialContent, + _dragPhotoTextInitialContent, + _dropPhotosHere, + _errorCorruptedPhotoUploaded, + _errorFileExcededMaxSize, + _errorFormatPhotoUploaded, + _errorInitialPhotoDownloadError, + _limitPhotosUploaded, + _limitPhotosUploadedNotification, + _mainPhotoLabel, + _maxPhotos, + _notificationErrorFormatPhotoUploaded, + _rotationDirection, + _uploadingPhotosText, + initialPhotos +} from '../config.js' +import { + _addMorePhotosIcon, + _deleteIcon, + _dragPhotosIcon, + _infoIcon, + _rejectPhotosIcon, + _retryErrorPhotosIcon, + _rotateIcon +} from '../icons.js' + +const DefaultArticle = ({className}) => { + return ( +
+

Initial Photos

+ + A set of initial images can be load with an array of URLs passed by + props. + + + After they are loaded, the images can be sorted, rotated or deleted from + the list. + + + This example has an array of URLs passed by props, and the third one + fails on load, so it shows an error notification. + + + Also, in this example we're blocking .bmp images, which are accepted by + default. + + + Also, rotation direction is set to clockwise. rotateIcon not changed, + though :P + + + Also, dragDelay time set to 0, it must be 0 to improve user experience + in desktop! + + +
+ ) +} + +DefaultArticle.displayName = 'DefaultArticle' + +DefaultArticle.propTypes = { + className: PropTypes.string +} + +export default DefaultArticle diff --git a/components/molecule/fileUploader/demo/articles/WithContentArticle.js b/components/molecule/fileUploader/demo/articles/WithContentArticle.js new file mode 100644 index 0000000000..a185fedae4 --- /dev/null +++ b/components/molecule/fileUploader/demo/articles/WithContentArticle.js @@ -0,0 +1,135 @@ +import {useState} from 'react' + +import PropTypes from 'prop-types' + +import {Article, H2, Paragraph} from '@s-ui/documentation-library' +import MoleculeSelectOption from '@s-ui/react-molecule-dropdown-option' +import MoleculeSelect from '@s-ui/react-molecule-select' + +import MoleculePhotoUploader from '../../src/index.js' +import { + _addPhotoTextButton, + _addPhotoTextSkeleton, + _allowUploadDuplicatedPhotos, + _callbackPhotosRejected, + _callbackPhotosUploaded, + _callbackUploadPhoto, + _dragDelay, + _dragPhotoDividerTextInitialContent, + _dragPhotoTextInitialContent, + _dropPhotosHere, + _errorCorruptedPhotoUploaded, + _errorFileExcededMaxSize, + _errorFormatPhotoUploaded, + _errorInitialPhotoDownloadError, + _limitPhotosUploaded, + _limitPhotosUploadedNotification, + _mainPhotoLabel, + _maxPhotos, + _notificationErrorFormatPhotoUploaded, + _rotationDirection, + _uploadingPhotosText, + initialFormValues, + initialPhotos, + labels, + labelsPlaceholder +} from '../config.js' +import { + _addMorePhotosIcon, + _deleteIcon, + _dragPhotosIcon, + _infoIcon, + _labelsArrowIcon, + _rejectPhotosIcon, + _retryErrorPhotosIcon, + _rotateIcon +} from '../icons.js' + +const DefaultArticle = ({className}) => { + const [formState, setFormState] = useState(initialFormValues) + + const handlePhotosChange = ({file: {label}}, index) => { + setFormState( + formState.map((currentLabel, i) => (index === i ? {label} : currentLabel)) + ) + } + + // eslint-disable-next-line react/prop-types + const _content = ({file, index}) => ( +
+ + handlePhotosChange({file: {...file, label: value}}, index) + } + iconArrowDown={_labelsArrowIcon()} + placeholder={labelsPlaceholder} + > + {labels.map(label => ( + + {label} + + ))} + +
+ ) + + return ( +
+

With Content - Select example

+ Use Content prop to show a select as example. + { + if (action.action === 'DELETE') { + const { + data: {itemIndex} + } = action + formState.splice(itemIndex, 1) + setFormState(formState) + } + _callbackPhotosUploaded(files, action, ...args) + }} + callbackUploadPhoto={_callbackUploadPhoto} + content={_content} + deleteIcon={_deleteIcon} + dragDelay={_dragDelay} + dragPhotosIcon={_dragPhotosIcon} + dragPhotoTextInitialContent={_dragPhotoTextInitialContent} + dragPhotoDividerTextInitialContent={_dragPhotoDividerTextInitialContent} + dropPhotosHereText={_dropPhotosHere} + errorCorruptedPhotoUploadedText={_errorCorruptedPhotoUploaded} + errorFileExcededMaxSizeText={_errorFileExcededMaxSize} + errorFormatPhotoUploadedText={_errorFormatPhotoUploaded} + errorInitialPhotoDownloadErrorText={_errorInitialPhotoDownloadError} + infoIcon={_infoIcon} + initialPhotos={initialPhotos} + limitPhotosUploadedText={_limitPhotosUploaded} + limitPhotosUploadedNotification={_limitPhotosUploadedNotification} + mainPhotoLabel={_mainPhotoLabel} + maxPhotos={_maxPhotos} + notificationErrorFormatPhotoUploaded={ + _notificationErrorFormatPhotoUploaded + } + rejectPhotosIcon={_rejectPhotosIcon} + retryIcon={_retryErrorPhotosIcon} + rotateIcon={_rotateIcon} + rotationDirection={_rotationDirection} + uploadingPhotosText={_uploadingPhotosText} + /> +
+ ) +} + +DefaultArticle.displayName = 'DefaultArticle' + +DefaultArticle.propTypes = { + className: PropTypes.string +} + +export default DefaultArticle diff --git a/components/molecule/fileUploader/demo/index.js b/components/molecule/fileUploader/demo/index.js new file mode 100644 index 0000000000..798c2692f5 --- /dev/null +++ b/components/molecule/fileUploader/demo/index.js @@ -0,0 +1,46 @@ +import {useState} from 'react' + +import {Code, H1, Paragraph} from '@s-ui/documentation-library' + +import File from '../src/component/File/index.js' +import FileModel from '../src/Model/FileModel.js' + +import {log} from './settings.js' + +const Demo = () => { + const [files, setFiles] = useState([]) + const changeHandler = async event => { + const responses = await Promise.allSettled( + Array.from(event.target.files).map(file => new FileModel(file)) + ) + setFiles(responses.map(response => response.value)) + } + const onCreateHandler = log('onCreate') + const onUpdateHandler = log('onUpdate') + const onDeleteHandler = log('onDelete') + + return ( +
+

Photo Uploader

+ + MoleculePhotoUploader is a component that lets you drag and + drop images on it, or click it to add images. Also, on mobile, let you + add photos directly taken with the camera. + + {files.map((file, index) => ( + + ))} + +
+ ) +} + +export default Demo diff --git a/components/molecule/fileUploader/demo/index.scss b/components/molecule/fileUploader/demo/index.scss new file mode 100644 index 0000000000..4a08ac6f6f --- /dev/null +++ b/components/molecule/fileUploader/demo/index.scss @@ -0,0 +1 @@ +@import '../src/index'; \ No newline at end of file diff --git a/components/molecule/fileUploader/demo/package.json b/components/molecule/fileUploader/demo/package.json new file mode 100644 index 0000000000..a4590b0f11 --- /dev/null +++ b/components/molecule/fileUploader/demo/package.json @@ -0,0 +1,14 @@ +{ + "name": "@s-ui/react-molecule-file-uploader-demo", + "version": "1.1.0", + "description": "", + "main": "index.js", + "private": true, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": {} +} diff --git a/components/molecule/fileUploader/demo/settings.js b/components/molecule/fileUploader/demo/settings.js new file mode 100644 index 0000000000..b9cf27a297 --- /dev/null +++ b/components/molecule/fileUploader/demo/settings.js @@ -0,0 +1,4 @@ +export const log = + message => + (...args) => + console.log(message, ...args) diff --git a/components/molecule/fileUploader/package.json b/components/molecule/fileUploader/package.json new file mode 100644 index 0000000000..50b6c707f9 --- /dev/null +++ b/components/molecule/fileUploader/package.json @@ -0,0 +1,22 @@ +{ + "name": "@s-ui/react-molecule-file-uploader", + "version": "1.0.0", + "description": "", + "main": "lib/index.js", + "scripts": { + "prepublishOnly": "rimraf ./lib && npm run build:js && npm run build:styles", + "build:js": "babel --presets sui ./src --out-dir ./lib", + "build:styles": "cpx './src/**/*.scss' ./lib" + }, + "dependencies": { + "@s-ui/react-atom-icon": "1.18.0", + "@s-ui/react-primitive-injector": "1", + "buffer": "6.0.3" + }, + "peerDependencies": { + "@s-ui/component-dependencies": "1" + }, + "keywords": [], + "author": "", + "license": "MIT" +} diff --git a/components/molecule/fileUploader/src/Model/FileModel.js b/components/molecule/fileUploader/src/Model/FileModel.js new file mode 100644 index 0000000000..206c511c40 --- /dev/null +++ b/components/molecule/fileUploader/src/Model/FileModel.js @@ -0,0 +1,92 @@ +import { + arrayBuffer2string, + string2arrayBuffer, + binary2string, + read, + FILE_READER, + READY_STATE, + STATUS +} from './helpers.js' + +class FileModel { + static FILE_READER = FILE_READER + static READY_STATE = READY_STATE + static STATUS = STATUS + + static arrayBuffer2string = arrayBuffer2string + static string2arrayBuffer = string2arrayBuffer + static binary2string = binary2string + + static read = read + + #defaultName + #name + #defaultValue + #value + #status + constructor(...args) { + const resolver = async function (resolve) { + let value, name + if (typeof args[0] === 'object' && args[0] instanceof File) { + const fileReader = await read(args[0]) + value = fileReader.result + name = args[0].name + } else { + ;[value, name] = args + } + this.#defaultName = name + this.#name = name + this.#defaultValue = value + this.#value = value + this.#status = + value === undefined ? FileModel.STATUS.EMPTY : FileModel.STATUS.READY + resolve(this) + } + + return new Promise(resolver.bind(this)) + } + + get [Symbol.toStringTag]() { + return 'FileView' + } + + get status() { + return this.#status + } + + get value() { + return this.#value + } + + get defaultValue() { + return this.#defaultValue + } + + get name() { + return this.#name + } + + set name(name) { + this.#name = name + } + + get defaultName() { + return this.#defaultName + } + + get() { + return { + name: this.#name, + value: this.#value, + status: this.#status + } + } + + set(...args) {} + + update(...args) {} + + render() {} +} + +export default FileModel diff --git a/components/molecule/fileUploader/src/Model/helpers.js b/components/molecule/fileUploader/src/Model/helpers.js new file mode 100644 index 0000000000..6f9ddf44d3 --- /dev/null +++ b/components/molecule/fileUploader/src/Model/helpers.js @@ -0,0 +1,86 @@ +import {Buffer} from 'buffer' + +export const FILE_READER = { + DATA_URL: 'readAsDataURL', // Starts reading the contents of the specified Blob, once finished, the result attribute contains a data: URL representing the file's data. + ARRAY_BUFFER: 'readAsArrayBuffer', // Starts reading the contents of the specified Blob, once finished, the result attribute contains an ArrayBuffer representing the file's data. + // BINARY_STRING: 'readAsBinaryString', // Starts reading the contents of the specified Blob, once finished, the result attribute contains the raw binary data from the file as a string. + TEXT: 'readAsText' // Starts reading the contents of the specified Blob, once finished, the result attribute contains the contents of the file as a text string. An optional encoding name can be specified. +} +export const READY_STATE = { + EMPTY: 0, // No data has been loaded yet. + LOADING: 1, // Data is currently being loaded. + DONE: 2 // The entire read request has been completed. +} +export const STATUS = { + EMPTY: 'empty', + READY: 'ready', + CREATED: 'created', + UPDATED: 'updated', + REMOVED: 'removed', +} + +export const arrayBuffer2string = (buffer, encoding = 'utf8') => + Buffer.from(buffer).toString(encoding) +export const string2arrayBuffer = string => { + let buffer = new ArrayBuffer(string.length * 2) // 2 bytes for each char + let bufferView = new Uint16Array(buffer) + for (let i = 0, strLen = string.length; i < strLen; i++) { + bufferView[i] = string.charCodeAt(i) + } + return buffer +} +export const binary2string = binary => + binary + .split(' ') + .map(elem => String.fromCharCode(parseInt(elem, 2))) + .join('') + +export const read = ( + file, + resolver = reader => { + return new Promise((resolve, reject) => { + reader.onload = event => { + resolve(event.target) + } + reader.onerror = error => { + debugger + reject(error) + } + }) + }, + [fileReader = FILE_READER.DATA_URL, options] = [] +) => { + const reader = new FileReader() + const { + /** Properties **/ + // error, + // readyState, + // result, + /** methods **/ + // readAsDataURL, + // readAsArrayBuffer, + // readAsBinaryString, + // readAsText, + // abort + /** events **/ + // onabort, + // onloadstart, + // onload, + // onloadend, + // onerror, + // onprogress + } = reader + + return new Promise((resolve, reject) => { + resolver(reader) + .then(response => resolve(response)) + .catch(error => reject(error)) + if (typeof reader[fileReader] === 'function') { + try { + reader[fileReader](file, options) + } catch (error) { + reject(error) + } + } + }) +} diff --git a/components/molecule/fileUploader/src/component/File/DefaultFile.js b/components/molecule/fileUploader/src/component/File/DefaultFile.js new file mode 100644 index 0000000000..8810d1a72d --- /dev/null +++ b/components/molecule/fileUploader/src/component/File/DefaultFile.js @@ -0,0 +1,48 @@ +import {forwardRef, useRef} from 'react' + +import PropTypes from 'prop-types' +import FileModel from '../../Model/FileModel.js' + +import {CLASS_FILE_DEFAULT} from './settings.js' +import {FILE_ACTIONS} from './FileAction/index.js' +import {download} from '../../settings.js' + +const DefaultFile = forwardRef( + ({status, name, value, target, onClick, ...props}, forwardedRef) => { + const innerRef = useRef() + return ( + + +
{name && `.${name.split('.').at(-1)}`}
+
+ {name} + + + download(value, {filename: name, target})} + /> + {status !== FileModel.STATUS.READY && } + + + {status} +
+ ) + } +) + +DefaultFile.displayName = 'DefaultFile' +DefaultFile.propTypes = { + status: PropTypes.string, + name: PropTypes.string, + value: PropTypes.string +} + +export default DefaultFile diff --git a/components/molecule/fileUploader/src/component/File/File.js b/components/molecule/fileUploader/src/component/File/File.js new file mode 100644 index 0000000000..8a6831d138 --- /dev/null +++ b/components/molecule/fileUploader/src/component/File/File.js @@ -0,0 +1,60 @@ +import {forwardRef, Fragment, useEffect} from 'react' +import {isFragment} from 'react-is' + +import PropTypes from 'prop-types' + +import useMountedState from '@s-ui/react-hooks/lib/useMountedState' + +import Injector from '@s-ui/react-primitive-injector' +import FileModel from '../../Model/FileModel.js' + +import {BASE_CLASS, trigger} from './settings.js' +import DefaultFile from './DefaultFile.js' + +const File = forwardRef( + ( + { + as: As = Fragment, + value, + status, + name, + children = , + onUpdate, + onCreate, + onDelete, + ...props + }, + forwardedRef + ) => { + const getIsMounted = useMountedState() + + useEffect(() => { + const isMounted = getIsMounted() + isMounted + ? trigger(onCreate)({value, status, name}) + : trigger(onUpdate)({value, status, name}) + return () => trigger(onDelete)({value, status, name}) + }, [value, status, name]) + + return ( + ) && {className: BASE_CLASS, ref: forwardedRef})} + > + + {children} + + + ) + } +) + +File.displayName = 'File' + +File.propTypes = { + value: PropTypes.string, + name: PropTypes.string, + status: PropTypes.oneOf(Object.values(FileModel.STATUS)), + children: PropTypes.node +} + +export default File diff --git a/components/molecule/fileUploader/src/component/File/FileAction/FileAction.js b/components/molecule/fileUploader/src/component/File/FileAction/FileAction.js new file mode 100644 index 0000000000..17926f49f9 --- /dev/null +++ b/components/molecule/fileUploader/src/component/File/FileAction/FileAction.js @@ -0,0 +1,27 @@ +import PropTypes from 'prop-types' + +import Icon, {atomIconSizes, atomIconColors} from '@s-ui/react-atom-icon' + +import {CLASS_FILE_ACTION} from './settings.js' + +const FileAction = ({ + children, + size = atomIconSizes.medium, + color = atomIconColors.primary, + ...props +}) => { + return ( + + + {children} + + + ) +} + +FileAction.dosplayName = 'FileAction' +FileAction.propTypes = { + children: PropTypes.node +} + +export default FileAction diff --git a/components/molecule/fileUploader/src/component/File/FileAction/Icons/download.js b/components/molecule/fileUploader/src/component/File/FileAction/Icons/download.js new file mode 100644 index 0000000000..abd511d4d0 --- /dev/null +++ b/components/molecule/fileUploader/src/component/File/FileAction/Icons/download.js @@ -0,0 +1,6 @@ +export default ( + + + + +) diff --git a/components/molecule/fileUploader/src/component/File/FileAction/Icons/index.js b/components/molecule/fileUploader/src/component/File/FileAction/Icons/index.js new file mode 100644 index 0000000000..d5b357e947 --- /dev/null +++ b/components/molecule/fileUploader/src/component/File/FileAction/Icons/index.js @@ -0,0 +1,7 @@ +import download from './download.js' +import recover from './recover.js' +import remove from './remove.js' +import show from './show.js' +import upload from './upload.js' + +export {download, recover, remove, show, upload} diff --git a/components/molecule/fileUploader/src/component/File/FileAction/Icons/recover.js b/components/molecule/fileUploader/src/component/File/FileAction/Icons/recover.js new file mode 100644 index 0000000000..baf7f68954 --- /dev/null +++ b/components/molecule/fileUploader/src/component/File/FileAction/Icons/recover.js @@ -0,0 +1,5 @@ +export default ( + + + +) diff --git a/components/molecule/fileUploader/src/component/File/FileAction/Icons/remove.js b/components/molecule/fileUploader/src/component/File/FileAction/Icons/remove.js new file mode 100644 index 0000000000..ea89da9da1 --- /dev/null +++ b/components/molecule/fileUploader/src/component/File/FileAction/Icons/remove.js @@ -0,0 +1,5 @@ +export default ( + + + +) diff --git a/components/molecule/fileUploader/src/component/File/FileAction/Icons/show.js b/components/molecule/fileUploader/src/component/File/FileAction/Icons/show.js new file mode 100644 index 0000000000..e6544d2610 --- /dev/null +++ b/components/molecule/fileUploader/src/component/File/FileAction/Icons/show.js @@ -0,0 +1,6 @@ +export default ( + + + + +) diff --git a/components/molecule/fileUploader/src/component/File/FileAction/Icons/upload.js b/components/molecule/fileUploader/src/component/File/FileAction/Icons/upload.js new file mode 100644 index 0000000000..5fdc0f75ef --- /dev/null +++ b/components/molecule/fileUploader/src/component/File/FileAction/Icons/upload.js @@ -0,0 +1,6 @@ +export default ( + + + + +) diff --git a/components/molecule/fileUploader/src/component/File/FileAction/fileActions.js b/components/molecule/fileUploader/src/component/File/FileAction/fileActions.js new file mode 100644 index 0000000000..b8cb284f84 --- /dev/null +++ b/components/molecule/fileUploader/src/component/File/FileAction/fileActions.js @@ -0,0 +1,16 @@ +import FileAction from './FileAction.js' +import { + download as downloadIcon, + recover as recoverIcon, + remove as removeIcon, + show as showIcon +} from './Icons' + +import {download} from '../../../settings.js' + +export const FILE_ACTIONS = { + Download: ({onClick}) => {downloadIcon}, + Recover: () => {recoverIcon}, + Remove: () => {removeIcon}, + Show: () => {showIcon} +} diff --git a/components/molecule/fileUploader/src/component/File/FileAction/index.js b/components/molecule/fileUploader/src/component/File/FileAction/index.js new file mode 100644 index 0000000000..f089436f1f --- /dev/null +++ b/components/molecule/fileUploader/src/component/File/FileAction/index.js @@ -0,0 +1,5 @@ +import FileAction from './FileAction.js' + +export { FILE_ACTIONS } from './fileActions.js' + +export default FileAction \ No newline at end of file diff --git a/components/molecule/fileUploader/src/component/File/FileAction/settings.js b/components/molecule/fileUploader/src/component/File/FileAction/settings.js new file mode 100644 index 0000000000..0ebfc51550 --- /dev/null +++ b/components/molecule/fileUploader/src/component/File/FileAction/settings.js @@ -0,0 +1,3 @@ +import {BASE_CLASS} from '../settings.js' + +export const CLASS_FILE_ACTION = `${BASE_CLASS}-Action` \ No newline at end of file diff --git a/components/molecule/fileUploader/src/component/File/index.js b/components/molecule/fileUploader/src/component/File/index.js new file mode 100644 index 0000000000..39e18ac12d --- /dev/null +++ b/components/molecule/fileUploader/src/component/File/index.js @@ -0,0 +1,3 @@ +import File from './File.js' + +export default File \ No newline at end of file diff --git a/components/molecule/fileUploader/src/component/File/settings.js b/components/molecule/fileUploader/src/component/File/settings.js new file mode 100644 index 0000000000..4f3f4250b9 --- /dev/null +++ b/components/molecule/fileUploader/src/component/File/settings.js @@ -0,0 +1,7 @@ +export const BASE_CLASS = 'sui-atomFile' + +export const CLASS_FILE_DEFAULT = `${BASE_CLASS}-Default` + +export const isFunction = fn => typeof fn === 'function' + +export const trigger = fn => (isFunction(fn) ? fn : () => null) diff --git a/components/molecule/fileUploader/src/component/FileList/FileList.js b/components/molecule/fileUploader/src/component/FileList/FileList.js new file mode 100644 index 0000000000..4ada8823ce --- /dev/null +++ b/components/molecule/fileUploader/src/component/FileList/FileList.js @@ -0,0 +1,40 @@ +import {forwardRef, Fragment} from 'react' +import {isFragment} from 'react-is' + +import PropTypes from 'prop-types' + +import Injector from '@s-ui/react-primitive-injector' + +import {BASE_CLASS} from './settings.js' + +const FileList = forwardRef( +( +{as: As = Fragment, value, status, name, onChange, ...props}, +forwardedRef +) => { + return ( + ) && {className: BASE_CLASS, ref: forwardedRef})} + > + + {children} + + + ) +} +) + +FileList.displayName = 'FileList' + +FileList.propTypes = { + value: PropTypes.string, + name: PropTypes.string +} + +export default FileList diff --git a/components/molecule/fileUploader/src/component/FileList/index.js b/components/molecule/fileUploader/src/component/FileList/index.js new file mode 100644 index 0000000000..207beaa6f1 --- /dev/null +++ b/components/molecule/fileUploader/src/component/FileList/index.js @@ -0,0 +1,3 @@ +import FileList from './FileList.js' + +export default FileList \ No newline at end of file diff --git a/components/molecule/fileUploader/src/component/FileList/settings.js b/components/molecule/fileUploader/src/component/FileList/settings.js new file mode 100644 index 0000000000..98b039e3dd --- /dev/null +++ b/components/molecule/fileUploader/src/component/FileList/settings.js @@ -0,0 +1,3 @@ +export const BASE_CLASS = 'sui-atomFileList' + +export const BASE_CLASS_DEFAULT = `${BASE_CLASS}-Default` diff --git a/components/molecule/fileUploader/src/index.js b/components/molecule/fileUploader/src/index.js new file mode 100644 index 0000000000..597219cfdd --- /dev/null +++ b/components/molecule/fileUploader/src/index.js @@ -0,0 +1,13 @@ +import PropTypes from 'prop-types' + +import {download} from './settings.js' + +const FileUploader = () => { + return null +} + +FileUploader.displayName = 'FileUploader' + +export default FileUploader + +export {download} diff --git a/components/molecule/fileUploader/src/index.scss b/components/molecule/fileUploader/src/index.scss new file mode 100644 index 0000000000..b4138bf089 --- /dev/null +++ b/components/molecule/fileUploader/src/index.scss @@ -0,0 +1,3 @@ +@import '~@s-ui/theme/lib/index'; + +@import "~@s-ui/react-atom-icon/lib/index"; \ No newline at end of file diff --git a/components/molecule/fileUploader/src/settings.js b/components/molecule/fileUploader/src/settings.js new file mode 100644 index 0000000000..38749b3886 --- /dev/null +++ b/components/molecule/fileUploader/src/settings.js @@ -0,0 +1,12 @@ +export const download = ( + base64DataURLString, + {filename, target = '_self'} = {} +) => { + const downloadLink = document.createElement('a') + downloadLink.href = base64DataURLString + downloadLink.target = target + downloadLink.download = filename + document.body.appendChild(downloadLink) + downloadLink.click() + document.body.removeChild(downloadLink) +} diff --git a/components/molecule/fileUploader/test/index.test.js b/components/molecule/fileUploader/test/index.test.js new file mode 100644 index 0000000000..90c7e57162 --- /dev/null +++ b/components/molecule/fileUploader/test/index.test.js @@ -0,0 +1,704 @@ +/* + * Remember: YOUR COMPONENT IS DEFINED GLOBALLY + * */ + +/* eslint react/jsx-no-undef:0 */ +/* eslint no-undef:0 */ + +import {demoBaseClassName} from '@s-ui/react-primitive-injector-demo/settings.js' +import ReactDOM from 'react-dom' + +import chai, {expect} from 'chai' +import chaiDOM from 'chai-dom' +// import sinon from 'sinon' + +import json from '../package.json' +import * as pkg from '../src/index.js' + +import FileModel from '../src/Model/FileModel.js' + +chai.use(chaiDOM) + +describe('Model', () => { + describe('FileModel', () => { + const fileContent = 'fileContent' + const name = 'filename' + const fileExtension = 'txt' + const fileName = `${name}.${fileExtension}` + + describe('statics', () => { + describe('FILE_READER', () => { + it('value must be an object enum', () => { + // Given + + // When + const {FILE_READER: actual} = FileModel + + // Then + expect(actual).to.be.an('object') + }) + + it('value must be a defined string-key pair filled', () => { + // Given + const expected = { + DATA_URL: 'readAsDataURL', + ARRAY_BUFFER: 'readAsArrayBuffer', + // BINARY_STRING: 'readAsBinaryString', + TEXT: 'readAsText' + } + + // When + const {FILE_READER: actual} = FileModel + const { + DATA_URL, + ARRAY_BUFFER, + // BINARY_STRING, + TEXT, + ...others + } = actual + + // Then + expect(Object.keys(others).length).to.equal(0) + expect(Object.keys(actual)).to.have.members(Object.keys(expected)) + Object.entries(expected).forEach(([expectedKey, expectedValue]) => { + expect(Object.keys(actual).includes(expectedKey)).to.be.true + expect(actual[expectedKey]).to.equal(expectedValue) + }) + }) + }) + + describe('READY_STATE', () => { + it('value must be an object enum', () => { + // Given + + // When + const {READY_STATE: actual} = FileModel + + // Then + expect(actual).to.be.an('object') + }) + + it('value must be a defined string-key pair filled', () => { + // Given + const expected = { + EMPTY: 0, + LOADING: 1, + DONE: 2 + } + + // When + const {READY_STATE: actual} = FileModel + const {EMPTY, LOADING, DONE, ...others} = actual + + // Then + expect(Object.keys(others).length).to.equal(0) + expect(Object.keys(actual)).to.have.members(Object.keys(expected)) + Object.entries(expected).forEach(([expectedKey, expectedValue]) => { + expect(Object.keys(actual).includes(expectedKey)).to.be.true + expect(actual[expectedKey]).to.equal(expectedValue) + }) + }) + }) + + describe('read', () => { + it('given a file should return the data', async () => { + // Given + const file = new File([fileContent], fileName) + + // When + const {error, readyState, result, ...others} = await FileModel.read( + file + ) + // Then + expect(error).to.be.null + expect(readyState).to.equal(FileModel.READY_STATE.DONE) + expect(Object.keys(others).length).to.equal(0) + expect(result).to.be.string + expect(atob(result.split(',')[1])).to.equal(fileContent) + }) + + it('given a file should return the data when file reader is data-url', async () => { + // Given + const file = new File([fileContent], fileName) + + // When + const {error, readyState, result, ...others} = await FileModel.read( + file, + FileModel.FILE_READER.DATA_URL.DATA_URL + ) + // Then + expect(error).to.be.null + expect(readyState).to.equal(FileModel.READY_STATE.DONE) + expect(Object.keys(others).length).to.equal(0) + expect(result).to.be.string + expect(atob(result.split(',')[1])).to.equal(fileContent) + }) + + it('given a file should return the data when file reader is array-buffer', async () => { + // Given + const file = new File([fileContent], fileName) + + // When + const {error, readyState, result, ...others} = await FileModel.read( + file, + undefined, + [FileModel.FILE_READER.ARRAY_BUFFER] + ) + // Then + expect(error).to.be.null + expect(readyState).to.equal(FileModel.READY_STATE.DONE) + expect(Object.keys(others).length).to.equal(0) + expect(result).to.be.string + expect(FileModel.arrayBuffer2string(result)).to.equal(fileContent) + }) + + it('given a file should return the data when file reader is text', async () => { + // Given + const file = new File([fileContent], fileName) + + // When + const {error, readyState, result, ...others} = await FileModel.read( + file, + undefined, + [FileModel.FILE_READER.TEXT] + ) + // Then + expect(error).to.be.null + expect(readyState).to.equal(FileModel.READY_STATE.DONE) + expect(Object.keys(others).length).to.equal(0) + expect(result).to.be.string + expect(result).to.equal(fileContent) + }) + + it('given NOT a file should fire a reading error', async () => { + // Given + const file = 1 + + // When + + // Then + await FileModel.read(file).catch(error => { + expect(error.message).to.equal( + "Failed to execute 'readAsDataURL' on 'FileReader': parameter 1 is not of type 'Blob'." + ) + }) + }) + + it('given a file and aborting the loading should fire an error', async () => { + // Given + const file = new File([fileContent], fileName) + const resolver = reader => + new Promise((resolve, reject) => { + reader.onabort = event => { + reject(event.target.error) + } + reader.onloadstart = () => { + reader.abort() + } + }) + + // When + + // Then + await FileModel.read(file, resolver).catch(error => { + expect(error.message).to.equal( + 'An ongoing operation was aborted, typically with a call to abort().' + ) + }) + }) + }) + }) + + describe('constructor', async () => { + it('given undefined value should return an empty FileModel', async () => { + // Given + + // When + const current = await new FileModel(undefined, undefined) + + // Then + expect(Object.keys(current).length).to.equal(0) + expect(current.status).to.equal(FileModel.STATUS.EMPTY) + expect(current.value).to.be.undefined + expect(current.defaultValue).to.be.undefined + expect(current.name).to.be.undefined + expect(current.defaultName).to.be.undefined + }) + + it('given af File value should return a FileModel', async () => { + // Given + const file = new File([fileContent], fileName) + + // When + const current = await new FileModel(file) + + // Then + expect(Object.keys(current).length).to.equal(0) + expect(current.status).to.equal(FileModel.STATUS.READY) + expect(current.value).to.not.be.undefined + expect(current.defaultValue).to.not.be.undefined + expect(current.name).to.not.be.undefined + expect(current.name).to.equal(file.name) + expect(current.defaultName).to.not.be.undefined + expect(current.defaultName).to.equal(current.name) + }) + + it('given af FileReader result should return a FileModel', async () => { + // Given + const file = new File([fileContent], fileName) + const {result: base64FileData} = await FileModel.read(file) + + // When + const current = await new FileModel(base64FileData) + + // Then + expect(Object.keys(current).length).to.equal(0) + expect(current.status).to.equal(FileModel.STATUS.READY) + expect(current.value).to.not.be.undefined + expect(current.defaultValue).to.not.be.undefined + expect(current.name).to.be.undefined + expect(current.defaultName).to.be.undefined + expect(current.defaultName).to.equal(current.name) + }) + + it('given af FileReader rand its filename result should return a FileModel', async () => { + // Given + const file = new File([fileContent], fileName) + const {result: base64FileData} = await FileModel.read(file) + + // When + const current = await new FileModel(base64FileData, fileName) + + // Then + expect(Object.keys(current).length).to.equal(0) + expect(current.status).to.equal(FileModel.STATUS.READY) + expect(current.value).to.not.be.undefined + expect(current.defaultValue).to.not.be.undefined + expect(current.name).to.not.be.undefined + expect(current.name).to.equal(file.name) + expect(current.defaultName).to.not.be.undefined + expect(current.defaultName).to.equal(current.name) + }) + }) + describe('get', async () => { + it('given undefined value should get an empty object', async () => { + // Given + const expected = { + name: undefined, + value: undefined, + status: FileModel.STATUS.EMPTY + } + + // When + const current = await new FileModel(undefined, undefined) + const actual = current.get() + const {name, value, status, ...others} = actual + + // Then + expect(actual).to.be.an('object') + + // Then + expect(Object.keys(others).length).to.equal(0) + expect(Object.keys(actual)).to.have.members(Object.keys(expected)) + Object.entries(expected).forEach(([expectedKey, expectedValue]) => { + expect(Object.keys(actual).includes(expectedKey)).to.be.true + expect(actual[expectedKey]).to.equal(expectedValue) + }) + }) + it('given File value should get an object', async () => { + // Given + const file = new File([fileContent], fileName) + const expected = { + name: fileName, + value: `data:application/octet-stream;base64,${btoa(fileContent)}`, + status: FileModel.STATUS.READY + } + + // When + const current = await new FileModel(file) + const actual = current.get() + const {name, value, status, ...others} = actual + + // Then + expect(actual).to.be.an('object') + + // Then + expect(Object.keys(others).length).to.equal(0) + expect(Object.keys(actual)).to.have.members(Object.keys(expected)) + Object.entries(expected).forEach(([expectedKey, expectedValue]) => { + expect(Object.keys(actual).includes(expectedKey)).to.be.true + expect(actual[expectedKey]).to.equal(expectedValue) + }) + }) + }) + describe('status', () => { + describe('get', () => { + it('given an empty file the status might be empty', async () => { + // Given + + // When + const current = await new FileModel(undefined, undefined) + + // Then + expect(current.status).to.equal(FileModel.STATUS.EMPTY) + }) + + it('given a file the status might be ready', async () => { + // Given + const file = new File([fileContent], fileName) + + // When + const current = await new FileModel(file) + + // Then + expect(current.status).to.equal(FileModel.STATUS.READY) + }) + + it('given a fileReader the status might be ready', async () => { + // Given + const file = new File([fileContent], fileName) + const {result: base64FileData} = await FileModel.read(file) + + // When + const current = await new FileModel(base64FileData) + + // Then + expect(current.status).to.equal(FileModel.STATUS.READY) + }) + }) + + describe('set', () => { + it('given an status the status might NOT change', async () => { + // Given + const status = FileModel.STATUS.READY + const fileModel = await new FileModel(undefined, undefined) + + // When + + // Then + expect(() => fileModel.status = status).to.throw('Cannot set property status of # which has only a getter') + }) + }) + }) + describe('value', () => { + describe('get', () => { + it('given an empty file the value might be empty', async () => { + // Given + + // When + const current = await new FileModel(undefined, undefined) + + // Then + expect(current.value).to.be.undefined + }) + + it('given a file the value might exist', async () => { + // Given + const file = new File([fileContent], fileName) + + // When + const current = await new FileModel(file) + + // Then + expect(current.value).to.not.be.undefined + expect(atob(current.value.split(',')[1])).to.equal(fileContent) + }) + + it('given a fileReader the value might exist', async () => { + // Given + const file = new File([fileContent], fileName) + const {result: base64FileData} = await FileModel.read(file) + + // When + const current = await new FileModel(base64FileData) + + // Then + expect(current.value).to.not.be.undefined + expect(atob(current.value.split(',')[1])).to.equal(fileContent) + }) + }) + + describe('set', () => { + it('given a value the value might NOT change', async () => { + // Given + const value = btoa(fileContent) + const fileModel = await new FileModel(undefined, undefined) + + // When + + // Then + expect(() => fileModel.value = value).to.throw('Cannot set property value of # which has only a getter') + }) + }) + }) + describe('defaultValue', () => { + describe('get', () => { + it('given an empty file the defaultValue might be empty', async () => { + // Given + + // When + const current = await new FileModel(undefined, undefined) + + // Then + expect(current.defaultValue).to.be.undefined + }) + + it('given a file the defaultValue might exist', async () => { + // Given + const file = new File([fileContent], fileName) + + // When + const current = await new FileModel(file) + + // Then + expect(current.defaultValue).to.not.be.undefined + expect(atob(current.defaultValue.split(',')[1])).to.equal(fileContent) + }) + + it('given a fileReader the defaultValue might exist', async () => { + // Given + const file = new File([fileContent], fileName) + const {result: base64FileData} = await FileModel.read(file) + + // When + const current = await new FileModel(base64FileData) + + // Then + expect(current.defaultValue).to.not.be.undefined + expect(atob(current.defaultValue.split(',')[1])).to.equal(fileContent) + }) + }) + + describe('set', () => { + it('given a value the defaultValue might NOT change', async () => { + // Given + const defaultValue = btoa(fileContent) + const fileModel = await new FileModel(undefined, undefined) + + // When + + // Then + expect(() => fileModel.defaultValue = defaultValue).to.throw('Cannot set property defaultValue of # which has only a getter') + }) + }) + }) + describe('name', () => { + describe('get', () => { + it('given an empty file the name might be empty', async () => { + // Given + + // When + const current = await new FileModel(undefined, undefined) + + // Then + expect(current.name).to.be.undefined + }) + + it('given an empty file and a name the name might NOT be undefined', async () => { + // Given + const filename = fileName + + // When + const current = await new FileModel(undefined, filename) + + // Then + expect(current.name).to.not.be.undefined + expect(current.name).to.equal(filename) + }) + + it('given a file the name might exist', async () => { + // Given + const file = new File([fileContent], fileName) + + // When + const current = await new FileModel(file) + + // Then + expect(current.name).to.not.be.undefined + expect(current.name).to.equal(fileName) + }) + + it('given a fileReader the name might NOT exist', async () => { + // Given + const file = new File([fileContent], fileName) + const {result: base64FileData} = await FileModel.read(file) + + // When + const current = await new FileModel(base64FileData) + + // Then + expect(current.name).to.be.undefined + }) + + it('given a fileReader and filename the name might exist', async () => { + // Given + const file = new File([fileContent], fileName) + const {result: base64FileData} = await FileModel.read(file) + + // When + const current = await new FileModel(base64FileData, fileName) + + // Then + expect(current.name).to.not.be.undefined + expect(current.name).to.equal(fileName) + }) + }) + + describe('set', () => { + it('given a value the value might NOT change', async () => { + // Given + const filename = 'newFilename' + const fileModel = await new FileModel(undefined, undefined) + + // When + fileModel.name = filename + + // Then + expect(fileModel.name).to.not.be.undefined + expect(fileModel.name).to.not.equal(fileName) + expect(fileModel.name).to.equal(filename) + }) + }) + }) + describe('defaultName', () => { + describe('get', () => { + it('given an empty file the defaultName might be empty', async () => { + // Given + + // When + const current = await new FileModel(undefined, undefined) + + // Then + expect(current.defaultName).to.be.undefined + }) + + it('given an empty file and a name the defaultName might NOT be undefined', async () => { + // Given + const filename = fileName + + // When + const current = await new FileModel(undefined, filename) + + // Then + expect(current.defaultName).to.not.be.undefined + expect(current.defaultName).to.equal(filename) + }) + + it('given a file the defaultName might exist', async () => { + // Given + const file = new File([fileContent], fileName) + + // When + const current = await new FileModel(file) + + // Then + expect(current.defaultName).to.not.be.undefined + expect(current.defaultName).to.equal(fileName) + }) + + it('given a fileReader the defaultName might NOT exist', async () => { + // Given + const file = new File([fileContent], fileName) + const {result: base64FileData} = await FileModel.read(file) + + // When + const current = await new FileModel(base64FileData) + + // Then + expect(current.defaultName).to.be.undefined + }) + + it('given a fileReader and filename the defaultName might exist', async () => { + // Given + const file = new File([fileContent], fileName) + const {result: base64FileData} = await FileModel.read(file) + + // When + const current = await new FileModel(base64FileData, fileName) + + // Then + expect(current.defaultName).to.not.be.undefined + expect(current.defaultName).to.equal(fileName) + }) + }) + + describe('set', () => { + it('given a value the defaultName might NOT change', async () => { + // Given + const defaultName = 'newDefaultName' + const fileModel = await new FileModel(undefined, undefined) + + // When + + // Then + expect(() => fileModel.defaultName = defaultName).to.throw('Cannot set property defaultName of # which has only a getter') + }) + }) + }) + }) +}) + +describe(json.name, () => { + const {default: Component} = pkg + const setup = setupEnvironment(Component) + + const IconElement = () => + + it('library should include defined exported elements', () => { + // Given + const library = pkg + const libraryExportedMembers = ['default'] + + // When + const {default: MoleculeFileUploader, ...others} = library + + // Then + expect(Object.keys(library).length).to.equal(libraryExportedMembers.length) + expect(Object.keys(library)).to.have.members(libraryExportedMembers) + expect(Object.keys(others).length).to.equal(0) + }) + + describe('File', () => {}) + + describe(Component.displayName, () => { + it('should render without crashing', () => { + // Given + const props = {} + + // When + const component = + + // Then + const div = document.createElement('div') + ReactDOM.render(component, div) + ReactDOM.unmountComponentAtNode(div) + }) + + it('should NOT render null', () => { + // Given + const props = {} + + // When + const {container} = setup(props) + + // Then + expect(container.innerHTML).to.be.a('string') + expect(container.innerHTML).to.not.have.lengthOf(0) + }) + + it('should NOT extend classNames', () => { + // Given + const props = {} + + const findSentence = str => string => + string.match(new RegExp(`S*${str}S*`)) + + // When + const {container} = setup(props) + const findClassName = findSentence(props.className) + + // Then + expect(findClassName(container.innerHTML)).to.be.null + }) + }) +}) diff --git a/package.json b/package.json index 90d8a16169..f5c5cc66bf 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,8 @@ "fs-extra": "10.0.1", "globby": "11.0.3", "sinon": "11.1.1", - "validate-commit-msg": "2.12.2" + "validate-commit-msg": "2.12.2", + "webpack-cli": "^4.10.0" }, "dependencies": { "@s-ui/component-dependencies": "1"