From 6a13ca1c0d7e9e6cd110b06735e506288ce86526 Mon Sep 17 00:00:00 2001 From: metonym Date: Mon, 21 Feb 2022 09:18:29 -0800 Subject: [PATCH 1/5] fix(file-uploader): correctly fire add/remove events (#1121) Fixes #1119 --- src/FileUploader/FileUploader.svelte | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/FileUploader/FileUploader.svelte b/src/FileUploader/FileUploader.svelte index cfbbb84e..f1d5f415 100644 --- a/src/FileUploader/FileUploader.svelte +++ b/src/FileUploader/FileUploader.svelte @@ -61,15 +61,28 @@ const dispatch = createEventDispatcher(); - $: prevFiles = []; + let prevFiles = []; + + /** @type {(file: File) => string} */ + const getFileId = (file) => file.lastModified + file.name; afterUpdate(() => { - if (files.length > prevFiles.length) { - dispatch("add", files); - } else { + const fileIds = files.map(getFileId); + const prevFileIds = prevFiles.map(getFileId); + const addedIds = fileIds.filter((_) => !prevFileIds.includes(_)); + const removedIds = prevFileIds.filter((_) => !fileIds.includes(_)); + + if (addedIds.length > 0) { + dispatch( + "add", + addedIds.map((id) => files.find((file) => id === getFileId(file))) + ); + } + + if (removedIds.length > 0) { dispatch( "remove", - prevFiles.filter((_) => !files.includes(_)) + removedIds.map((id) => prevFiles.find((file) => id === getFileId(file))) ); } From cd687f0e1bd46958501a6ab0c5dc6d32185b8dce Mon Sep 17 00:00:00 2001 From: metonym Date: Mon, 21 Feb 2022 09:24:37 -0800 Subject: [PATCH 2/5] refactor(types): remove unnecessary JSDoc default type [ci skip] (#1123) --- src/Search/Search.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Search/Search.svelte b/src/Search/Search.svelte index 4c7e7727..5cdd7fe4 100644 --- a/src/Search/Search.svelte +++ b/src/Search/Search.svelte @@ -12,7 +12,7 @@ /** * Specify the size of the search input - * @type {"sm" | "lg" | "xl"} [size="xl"] + * @type {"sm" | "lg" | "xl"} */ export let size = "xl"; From 2f3cff294228d29788f59d5450fe9de5606b0734 Mon Sep 17 00:00:00 2001 From: metonym Date: Mon, 21 Feb 2022 09:24:50 -0800 Subject: [PATCH 3/5] fix(file-uploader): update `clearFiles` accessor description (#1122) The `clearFiles` prop description currently reads "Override the default behavior of clearing the array of uploaded files." This is misleading as `clearFiles` is a component accessor, not a `let` prop. --- COMPONENT_INDEX.md | 26 ++++++++++----------- docs/src/COMPONENT_API.json | 2 +- src/FileUploader/FileUploader.svelte | 2 +- tests/FileUploader.test.svelte | 5 ++++ types/FileUploader/FileUploader.svelte.d.ts | 2 +- 5 files changed, 21 insertions(+), 16 deletions(-) diff --git a/COMPONENT_INDEX.md b/COMPONENT_INDEX.md index 49d2ea44..552489bb 100644 --- a/COMPONENT_INDEX.md +++ b/COMPONENT_INDEX.md @@ -1261,19 +1261,19 @@ None. ### Props -| Prop name | Kind | Reactive | Type | Default value | Description | -| :--------------- | :----------------- | :------- | :----------------------------------------------------------------------------------------- | --------------------------------------- | --------------------------------------------------------------------- | -| files | let | Yes | File[] | [] | Obtain the uploaded file names | -| status | let | No | "uploading" | "edit" | "complete" | "uploading" | Specify the file uploader status | -| accept | let | No | string[] | [] | Specify the accepted file types | -| multiple | let | No | boolean | false | Set to `true` to allow multiple files | -| clearFiles | const | No | () => void | () => { files = []; } | Override the default behavior of clearing the array of uploaded files | -| labelDescription | let | No | string | "" | Specify the label description | -| labelTitle | let | No | string | "" | Specify the label title | -| kind | let | No | "primary" | "secondary" | "tertiary" | "ghost" | "danger" | "primary" | Specify the kind of file uploader button | -| buttonLabel | let | No | string | "" | Specify the button label | -| iconDescription | let | No | string | "Provide icon description" | Specify the ARIA label used for the status icons | -| name | let | No | string | "" | Specify a name attribute for the file button uploader input | +| Prop name | Kind | Reactive | Type | Default value | Description | +| :--------------- | :----------------- | :------- | :----------------------------------------------------------------------------------------- | --------------------------------------- | ----------------------------------------------------------- | +| files | let | Yes | File[] | [] | Obtain the uploaded file names | +| status | let | No | "uploading" | "edit" | "complete" | "uploading" | Specify the file uploader status | +| accept | let | No | string[] | [] | Specify the accepted file types | +| multiple | let | No | boolean | false | Set to `true` to allow multiple files | +| clearFiles | const | No | () => void | () => { files = []; } | Programmatically clear the uploaded files | +| labelDescription | let | No | string | "" | Specify the label description | +| labelTitle | let | No | string | "" | Specify the label title | +| kind | let | No | "primary" | "secondary" | "tertiary" | "ghost" | "danger" | "primary" | Specify the kind of file uploader button | +| buttonLabel | let | No | string | "" | Specify the button label | +| iconDescription | let | No | string | "Provide icon description" | Specify the ARIA label used for the status icons | +| name | let | No | string | "" | Specify a name attribute for the file button uploader input | ### Slots diff --git a/docs/src/COMPONENT_API.json b/docs/src/COMPONENT_API.json index d908e0c6..f4b8198c 100644 --- a/docs/src/COMPONENT_API.json +++ b/docs/src/COMPONENT_API.json @@ -3503,7 +3503,7 @@ { "name": "clearFiles", "kind": "const", - "description": "Override the default behavior of clearing the array of uploaded files", + "description": "Programmatically clear the uploaded files", "type": "() => void", "value": "() => { files = []; }", "isFunction": true, diff --git a/src/FileUploader/FileUploader.svelte b/src/FileUploader/FileUploader.svelte index f1d5f415..fcb9c98a 100644 --- a/src/FileUploader/FileUploader.svelte +++ b/src/FileUploader/FileUploader.svelte @@ -27,7 +27,7 @@ export let multiple = false; /** - * Override the default behavior of clearing the array of uploaded files + * Programmatically clear the uploaded files * @type {() => void} */ export const clearFiles = () => { diff --git a/tests/FileUploader.test.svelte b/tests/FileUploader.test.svelte index a2eb96c5..e658fed8 100644 --- a/tests/FileUploader.test.svelte +++ b/tests/FileUploader.test.svelte @@ -6,6 +6,10 @@ FileUploaderItem, FileUploaderSkeleton, } from "../types"; + + let fileUploader: FileUploader; + + $: fileUploader?.clearFiles(); { /** - * Override the default behavior of clearing the array of uploaded files + * Programmatically clear the uploaded files */ clearFiles: () => void; } From 714f47a635654af4e3e496ec24a152ad0104b2cf Mon Sep 17 00:00:00 2001 From: metonym Date: Mon, 21 Feb 2022 09:42:42 -0800 Subject: [PATCH 4/5] fix(types): dispatched events without a detail value should be `null` (#1124) Currently, dispatched events without `e.detail` have a type of `any`. We can be more specific as a `CustomEvent` detail value is `null`. --- COMPONENT_INDEX.md | 88 +++++++++---------- docs/src/COMPONENT_API.json | 32 +++---- src/ImageLoader/ImageLoader.svelte | 4 +- src/LocalStorage/LocalStorage.svelte | 2 +- src/MultiSelect/MultiSelect.svelte | 2 +- src/Search/Search.svelte | 4 +- src/Tooltip/Tooltip.svelte | 4 +- .../TooltipDefinition.svelte | 4 +- src/UIShell/HeaderSearch.svelte | 6 +- src/UIShell/SideNav/SideNav.svelte | 6 +- tests/ImageLoader.test.svelte | 8 +- types/ImageLoader/ImageLoader.svelte.d.ts | 2 +- types/LocalStorage/LocalStorage.svelte.d.ts | 2 +- types/MultiSelect/MultiSelect.svelte.d.ts | 2 +- types/Search/Search.svelte.d.ts | 4 +- types/Tooltip/Tooltip.svelte.d.ts | 4 +- .../TooltipDefinition.svelte.d.ts | 4 +- types/UIShell/HeaderSearch.svelte.d.ts | 6 +- types/UIShell/SideNav/SideNav.svelte.d.ts | 6 +- 19 files changed, 97 insertions(+), 93 deletions(-) diff --git a/COMPONENT_INDEX.md b/COMPONENT_INDEX.md index 552489bb..e084be00 100644 --- a/COMPONENT_INDEX.md +++ b/COMPONENT_INDEX.md @@ -1863,9 +1863,9 @@ export interface HeaderSearchResult { | Event name | Type | Detail | | :--------- | :--------- | :---------------------------------------------------------------------------------------------- | -| active | dispatched | any | -| inactive | dispatched | any | -| clear | dispatched | any | +| active | dispatched | null | +| inactive | dispatched | null | +| clear | dispatched | null | | select | dispatched | { value: string; selectedResultIndex: number; selectedResult: HeaderSearchResult } | | change | forwarded | -- | | input | forwarded | -- | @@ -1956,10 +1956,10 @@ None. ### Events -| Event name | Type | Detail | -| :--------- | :--------- | :--------------- | -| load | dispatched | any | -| error | dispatched | any | +| Event name | Type | Detail | +| :--------- | :--------- | :---------------- | +| load | dispatched | null | +| error | dispatched | null | ## `InlineLoading` @@ -2274,7 +2274,7 @@ None. | Event name | Type | Detail | | :--------- | :--------- | :------------------------------------------- | -| save | dispatched | any | +| save | dispatched | null | | update | dispatched | { prevValue: any; value: any; } | ## `Modal` @@ -2464,7 +2464,7 @@ None. | :--------- | :--------- | :------------------------------------------------------------------------------------------------------------- | | blur | dispatched | FocusEvent | CustomEvent | | select | dispatched | { selectedIds: MultiSelectItemId[]; selected: MultiSelectItem[]; unselected: MultiSelectItem[]; } | -| clear | dispatched | any | +| clear | dispatched | null | | keydown | forwarded | -- | | keyup | forwarded | -- | | focus | forwarded | -- | @@ -3193,21 +3193,21 @@ None. ### Events -| Event name | Type | Detail | -| :--------- | :--------- | :--------------- | -| expand | dispatched | any | -| collapse | dispatched | any | -| click | forwarded | -- | -| mouseover | forwarded | -- | -| mouseenter | forwarded | -- | -| mouseleave | forwarded | -- | -| change | forwarded | -- | -| input | forwarded | -- | -| focus | forwarded | -- | -| blur | forwarded | -- | -| keydown | forwarded | -- | -| keyup | forwarded | -- | -| clear | dispatched | -- | +| Event name | Type | Detail | +| :--------- | :--------- | :---------------- | +| expand | dispatched | null | +| collapse | dispatched | null | +| click | forwarded | -- | +| mouseover | forwarded | -- | +| mouseenter | forwarded | -- | +| mouseleave | forwarded | -- | +| change | forwarded | -- | +| input | forwarded | -- | +| focus | forwarded | -- | +| blur | forwarded | -- | +| keydown | forwarded | -- | +| keyup | forwarded | -- | +| clear | dispatched | -- | ## `SearchSkeleton` @@ -3383,11 +3383,11 @@ None. ### Events -| Event name | Type | Detail | -| :------------ | :--------- | :--------------- | -| open | dispatched | any | -| close | dispatched | any | -| click:overlay | dispatched | any | +| Event name | Type | Detail | +| :------------ | :--------- | :---------------- | +| open | dispatched | null | +| close | dispatched | null | +| click:overlay | dispatched | null | ## `SideNavDivider` @@ -4679,12 +4679,12 @@ None. ### Events -| Event name | Type | Detail | -| :--------- | :--------- | :--------------- | -| open | dispatched | any | -| close | dispatched | any | -| click | forwarded | -- | -| mousedown | forwarded | -- | +| Event name | Type | Detail | +| :--------- | :--------- | :---------------- | +| open | dispatched | null | +| close | dispatched | null | +| click | forwarded | -- | +| mousedown | forwarded | -- | ## `TooltipDefinition` @@ -4708,15 +4708,15 @@ None. ### Events -| Event name | Type | Detail | -| :--------- | :--------- | :--------------- | -| open | dispatched | any | -| close | dispatched | any | -| click | forwarded | -- | -| mouseover | forwarded | -- | -| mouseenter | forwarded | -- | -| mouseleave | forwarded | -- | -| focus | forwarded | -- | +| Event name | Type | Detail | +| :--------- | :--------- | :---------------- | +| open | dispatched | null | +| close | dispatched | null | +| click | forwarded | -- | +| mouseover | forwarded | -- | +| mouseenter | forwarded | -- | +| mouseleave | forwarded | -- | +| focus | forwarded | -- | ## `TooltipFooter` diff --git a/docs/src/COMPONENT_API.json b/docs/src/COMPONENT_API.json index f4b8198c..7e30bf03 100644 --- a/docs/src/COMPONENT_API.json +++ b/docs/src/COMPONENT_API.json @@ -4915,9 +4915,9 @@ } ], "events": [ - { "type": "dispatched", "name": "active", "detail": "any" }, - { "type": "dispatched", "name": "inactive", "detail": "any" }, - { "type": "dispatched", "name": "clear", "detail": "any" }, + { "type": "dispatched", "name": "active", "detail": "null" }, + { "type": "dispatched", "name": "inactive", "detail": "null" }, + { "type": "dispatched", "name": "clear", "detail": "null" }, { "type": "dispatched", "name": "select", @@ -5115,8 +5115,8 @@ { "name": "loading", "default": false, "slot_props": "{}" } ], "events": [ - { "type": "dispatched", "name": "load", "detail": "any" }, - { "type": "dispatched", "name": "error", "detail": "any" } + { "type": "dispatched", "name": "load", "detail": "null" }, + { "type": "dispatched", "name": "error", "detail": "null" } ], "typedefs": [], "rest_props": { "type": "Element", "name": "img" } @@ -5920,7 +5920,7 @@ ], "slots": [], "events": [ - { "type": "dispatched", "name": "save", "detail": "any" }, + { "type": "dispatched", "name": "save", "detail": "null" }, { "type": "dispatched", "name": "update", @@ -6796,7 +6796,7 @@ "name": "select", "detail": "{ selectedIds: MultiSelectItemId[]; selected: MultiSelectItem[]; unselected: MultiSelectItem[]; }" }, - { "type": "dispatched", "name": "clear", "detail": "any" }, + { "type": "dispatched", "name": "clear", "detail": "null" }, { "type": "forwarded", "name": "keydown", "element": "input" }, { "type": "forwarded", "name": "keyup", "element": "input" }, { "type": "forwarded", "name": "focus", "element": "input" } @@ -9261,8 +9261,8 @@ } ], "events": [ - { "type": "dispatched", "name": "expand", "detail": "any" }, - { "type": "dispatched", "name": "collapse", "detail": "any" }, + { "type": "dispatched", "name": "expand", "detail": "null" }, + { "type": "dispatched", "name": "collapse", "detail": "null" }, { "type": "forwarded", "name": "click", "element": "SearchSkeleton" }, { "type": "forwarded", @@ -9831,9 +9831,9 @@ ], "slots": [{ "name": "__default__", "default": true, "slot_props": "{}" }], "events": [ - { "type": "dispatched", "name": "open", "detail": "any" }, - { "type": "dispatched", "name": "close", "detail": "any" }, - { "type": "dispatched", "name": "click:overlay", "detail": "any" } + { "type": "dispatched", "name": "open", "detail": "null" }, + { "type": "dispatched", "name": "close", "detail": "null" }, + { "type": "dispatched", "name": "click:overlay", "detail": "null" } ], "typedefs": [], "rest_props": { "type": "Element", "name": "nav" } @@ -13104,8 +13104,8 @@ } ], "events": [ - { "type": "dispatched", "name": "open", "detail": "any" }, - { "type": "dispatched", "name": "close", "detail": "any" }, + { "type": "dispatched", "name": "open", "detail": "null" }, + { "type": "dispatched", "name": "close", "detail": "null" }, { "type": "forwarded", "name": "click", "element": "div" }, { "type": "forwarded", "name": "mousedown", "element": "div" } ], @@ -13193,8 +13193,8 @@ } ], "events": [ - { "type": "dispatched", "name": "open", "detail": "any" }, - { "type": "dispatched", "name": "close", "detail": "any" }, + { "type": "dispatched", "name": "open", "detail": "null" }, + { "type": "dispatched", "name": "close", "detail": "null" }, { "type": "forwarded", "name": "click", "element": "button" }, { "type": "forwarded", "name": "mouseover", "element": "button" }, { "type": "forwarded", "name": "mouseenter", "element": "button" }, diff --git a/src/ImageLoader/ImageLoader.svelte b/src/ImageLoader/ImageLoader.svelte index 5835fd8a..a91d3f13 100644 --- a/src/ImageLoader/ImageLoader.svelte +++ b/src/ImageLoader/ImageLoader.svelte @@ -1,7 +1,7 @@