From 29beece408a4990cf2113ea76dcce42a6d64a49e Mon Sep 17 00:00:00 2001 From: Arno Wiest Date: Sat, 24 May 2025 20:13:40 +0200 Subject: [PATCH 1/8] chore: move popover dropdown component to ui lib and use bits-ui --- package-lock.json | 25 +++ package.json | 2 + src/docs/constants.ts | 2 + src/lib/components/Dropdown/Dropdown.svelte | 157 ++++++++++++++++++ src/routes/components/dropdown/+page.svelte | 15 ++ .../components/dropdown/BasicExample.svelte | 19 +++ 6 files changed, 220 insertions(+) create mode 100644 src/lib/components/Dropdown/Dropdown.svelte create mode 100644 src/routes/components/dropdown/+page.svelte create mode 100644 src/routes/components/dropdown/BasicExample.svelte diff --git a/package-lock.json b/package-lock.json index fba0cbdc..6f391383 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "dependencies": { "@mdi/js": "^7.4.47", "bits-ui": "^1.5.3", + "lodash-es": "^4.17.21", "tailwind-merge": "^2.5.4", "tailwind-variants": "^1.0.0" }, @@ -22,6 +23,7 @@ "@tailwindcss/postcss": "^4.1.7", "@tailwindcss/vite": "^4.1.7", "@types/eslint": "^9.6.0", + "@types/lodash-es": "^4.17.12", "autoprefixer": "^10.4.20", "eslint": "^9.7.0", "eslint-config-prettier": "^10.0.0", @@ -1678,6 +1680,23 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/lodash": { + "version": "4.17.17", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.17.tgz", + "integrity": "sha512-RRVJ+J3J+WmyOTqnz3PiBLA501eKwXl2noseKOrNo/6+XEHjTAxO4xHvxQB6QuNm+s4WRbn6rSiap8+EA+ykFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/lodash-es": { + "version": "4.17.12", + "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.12.tgz", + "integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/lodash": "*" + } + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "8.32.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.32.1.tgz", @@ -3993,6 +4012,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", + "license": "MIT" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", diff --git a/package.json b/package.json index bde12776..1cbcec17 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "@tailwindcss/postcss": "^4.1.7", "@tailwindcss/vite": "^4.1.7", "@types/eslint": "^9.6.0", + "@types/lodash-es": "^4.17.12", "autoprefixer": "^10.4.20", "eslint": "^9.7.0", "eslint-config-prettier": "^10.0.0", @@ -69,6 +70,7 @@ "dependencies": { "@mdi/js": "^7.4.47", "bits-ui": "^1.5.3", + "lodash-es": "^4.17.21", "tailwind-merge": "^2.5.4", "tailwind-variants": "^1.0.0" }, diff --git a/src/docs/constants.ts b/src/docs/constants.ts index 63728e3d..3b5221e6 100644 --- a/src/docs/constants.ts +++ b/src/docs/constants.ts @@ -18,6 +18,7 @@ import { mdiDotsCircle, mdiFormatHeaderPound, mdiFormDropdown, + mdiFormSelect, mdiFormTextbox, mdiFormTextboxPassword, mdiHelpBox, @@ -91,6 +92,7 @@ export const componentGroups = [ }, { name: 'PasswordInput', icon: mdiFormTextboxPassword }, { name: 'Select', icon: mdiFormDropdown }, + { name: 'Dropdown', icon: mdiFormSelect }, { name: 'Switch', icon: mdiToggleSwitchOutline, activeIcon: mdiToggleSwitch }, ], }, diff --git a/src/lib/components/Dropdown/Dropdown.svelte b/src/lib/components/Dropdown/Dropdown.svelte new file mode 100644 index 00000000..3b562a84 --- /dev/null +++ b/src/lib/components/Dropdown/Dropdown.svelte @@ -0,0 +1,157 @@ + + + + + + + + {#snippet child({ props })} + + {/snippet} + + + + {#snippet child({ props, wrapperProps, open })} + + {#if open} +
+
+ {#each options as option (option)} + {@const renderedOption = renderOption(option)} + {@const buttonStyle = renderedOption.disabled + ? '' + : 'transition-all hover:bg-gray-300 dark:hover:bg-gray-800'} + + {/each} +
+
+ {/if} + {/snippet} +
+
+
diff --git a/src/routes/components/dropdown/+page.svelte b/src/routes/components/dropdown/+page.svelte new file mode 100644 index 00000000..8fff3e07 --- /dev/null +++ b/src/routes/components/dropdown/+page.svelte @@ -0,0 +1,15 @@ + + + + + Allows the user to select a single option from a dropdown list that is triggered by a button + + + diff --git a/src/routes/components/dropdown/BasicExample.svelte b/src/routes/components/dropdown/BasicExample.svelte new file mode 100644 index 00000000..aad2e8db --- /dev/null +++ b/src/routes/components/dropdown/BasicExample.svelte @@ -0,0 +1,19 @@ + + + + {}} + render={({ label }) => ({ + title: label, + })} + /> + From b46280efc97a458bc9b2a1c9bebb8b2b375ea384 Mon Sep 17 00:00:00 2001 From: Arno Wiest Date: Sat, 24 May 2025 20:25:17 +0200 Subject: [PATCH 2/8] fix: remove unused imports --- src/routes/components/dropdown/+page.svelte | 1 - src/routes/components/dropdown/BasicExample.svelte | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/routes/components/dropdown/+page.svelte b/src/routes/components/dropdown/+page.svelte index 8fff3e07..f89e1c25 100644 --- a/src/routes/components/dropdown/+page.svelte +++ b/src/routes/components/dropdown/+page.svelte @@ -1,7 +1,6 @@ From 3c91ade329a085615bced402fa4a77287404fe32 Mon Sep 17 00:00:00 2001 From: Arno Wiest Date: Sun, 25 May 2025 10:38:29 +0200 Subject: [PATCH 3/8] fix: remove lodash dependency, add examples --- package-lock.json | 7 ---- package.json | 1 - src/lib/components/Dropdown/Dropdown.svelte | 25 +++++++----- src/routes/components/dropdown/+page.svelte | 16 +++++++- .../components/dropdown/BasicExample.svelte | 7 +--- src/routes/components/dropdown/BigList.svelte | 38 +++++++++++++++++++ .../components/dropdown/OutlineButton.svelte | 22 +++++++++++ 7 files changed, 93 insertions(+), 23 deletions(-) create mode 100644 src/routes/components/dropdown/BigList.svelte create mode 100644 src/routes/components/dropdown/OutlineButton.svelte diff --git a/package-lock.json b/package-lock.json index 6f391383..f9c9784c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,6 @@ "dependencies": { "@mdi/js": "^7.4.47", "bits-ui": "^1.5.3", - "lodash-es": "^4.17.21", "tailwind-merge": "^2.5.4", "tailwind-variants": "^1.0.0" }, @@ -4012,12 +4011,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lodash-es": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", - "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", - "license": "MIT" - }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", diff --git a/package.json b/package.json index 1cbcec17..32eacd48 100644 --- a/package.json +++ b/package.json @@ -70,7 +70,6 @@ "dependencies": { "@mdi/js": "^7.4.47", "bits-ui": "^1.5.3", - "lodash-es": "^4.17.21", "tailwind-merge": "^2.5.4", "tailwind-variants": "^1.0.0" }, diff --git a/src/lib/components/Dropdown/Dropdown.svelte b/src/lib/components/Dropdown/Dropdown.svelte index 3b562a84..a628c3e8 100644 --- a/src/lib/components/Dropdown/Dropdown.svelte +++ b/src/lib/components/Dropdown/Dropdown.svelte @@ -7,6 +7,7 @@ title: string; icon?: string; disabled?: boolean; + key: string | number; }; @@ -14,14 +15,14 @@ import { Button, Text } from '@immich/ui'; import { mdiCheck } from '@mdi/js'; import { Popover } from 'bits-ui'; - import { isEqual } from 'lodash-es'; import { fly } from 'svelte/transition'; import Icon from '../Icon/Icon.svelte'; + import type { ComponentProps } from 'svelte'; interface Props { class?: string; options: T[]; - selectedOption?: any; + selectedOption?: T; showMenu?: boolean; controlable?: boolean; hideTextOnSmallScreen?: boolean; @@ -31,6 +32,8 @@ onClickOutside?: () => void; render?: (item: T) => string | RenderedOption; fullWidthButton?: boolean; + buttonVariant?: ComponentProps['variant']; + buttonColor?: ComponentProps['color']; } let { @@ -46,6 +49,8 @@ onClickOutside = () => {}, render = String, fullWidthButton = true, + buttonVariant = 'ghost', + buttonColor = 'secondary', }: Props = $props(); const handleClickOutside = () => { @@ -67,19 +72,21 @@ const renderedOption = render(option); switch (typeof renderedOption) { case 'string': { - return { title: renderedOption }; + return { title: renderedOption, key: renderedOption }; } default: { return { title: renderedOption.title, icon: renderedOption.icon, disabled: renderedOption.disabled, + key: renderedOption.key, }; } } }; let renderedSelectedOption = $derived(renderOption(selectedOption)); + let renderedOptions = $derived(options.map(renderOption)); @@ -90,8 +97,8 @@ {...props} fullWidth={fullWidthButton} {title} - variant="ghost" - color="secondary" + variant={buttonVariant} + color={buttonColor} size="small" > {#if renderedSelectedOption?.icon} @@ -116,7 +123,7 @@
!renderedOption.disabled && handleSelectOption(option)} > - {#if isEqual(selectedOption, option)} -
+ {#if renderedSelectedOption.key === renderedOption.key} +
-

+

{renderedOption.title}

{:else} diff --git a/src/routes/components/dropdown/+page.svelte b/src/routes/components/dropdown/+page.svelte index f89e1c25..c606c7a7 100644 --- a/src/routes/components/dropdown/+page.svelte +++ b/src/routes/components/dropdown/+page.svelte @@ -4,11 +4,25 @@ import ComponentPage from '$docs/components/ComponentPage.svelte'; import BasicExample from './BasicExample.svelte'; import basicExample from './BasicExample.svelte?raw'; + import OutlineButton from './OutlineButton.svelte'; + import outlineButton from './OutlineButton.svelte?raw'; + import BigList from './BigList.svelte'; + import bigList from './BigList.svelte?raw'; Allows the user to select a single option from a dropdown list that is triggered by a button - + diff --git a/src/routes/components/dropdown/BasicExample.svelte b/src/routes/components/dropdown/BasicExample.svelte index 2043b69a..11908546 100644 --- a/src/routes/components/dropdown/BasicExample.svelte +++ b/src/routes/components/dropdown/BasicExample.svelte @@ -6,14 +6,11 @@ {}} render={({ label }) => ({ title: label, + key: label.toLowerCase(), })} /> diff --git a/src/routes/components/dropdown/BigList.svelte b/src/routes/components/dropdown/BigList.svelte new file mode 100644 index 00000000..881132d4 --- /dev/null +++ b/src/routes/components/dropdown/BigList.svelte @@ -0,0 +1,38 @@ + + + + {}} + render={({ label }) => ({ + title: label, + key: label.toLowerCase(), + })} + /> + diff --git a/src/routes/components/dropdown/OutlineButton.svelte b/src/routes/components/dropdown/OutlineButton.svelte new file mode 100644 index 00000000..8af92858 --- /dev/null +++ b/src/routes/components/dropdown/OutlineButton.svelte @@ -0,0 +1,22 @@ + + + + {}} + render={({ label, value }) => ({ + title: label, + key: value, + })} + /> + From de401872e94758ab3058b96448a61ed8c0414ef4 Mon Sep 17 00:00:00 2001 From: Arno Wiest Date: Sun, 25 May 2025 10:43:19 +0200 Subject: [PATCH 4/8] fix: removed unused variable --- src/lib/components/Dropdown/Dropdown.svelte | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib/components/Dropdown/Dropdown.svelte b/src/lib/components/Dropdown/Dropdown.svelte index a628c3e8..92b466b2 100644 --- a/src/lib/components/Dropdown/Dropdown.svelte +++ b/src/lib/components/Dropdown/Dropdown.svelte @@ -86,7 +86,6 @@ }; let renderedSelectedOption = $derived(renderOption(selectedOption)); - let renderedOptions = $derived(options.map(renderOption)); From d364fad2900abb506275dd2449a46f4d1ae277ff Mon Sep 17 00:00:00 2001 From: Arno Wiest Date: Sun, 25 May 2025 13:57:06 +0200 Subject: [PATCH 5/8] fix: remove lodash types --- package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/package.json b/package.json index 32eacd48..b8a035ae 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,6 @@ "@tailwindcss/postcss": "^4.1.7", "@tailwindcss/vite": "^4.1.7", "@types/eslint": "^9.6.0", - "@types/lodash-es": "^4.17.12", "autoprefixer": "^10.4.20", "eslint": "^9.7.0", "eslint-config-prettier": "^10.0.0", @@ -76,4 +75,4 @@ "volta": { "node": "22.15.1" } -} +} \ No newline at end of file From ceeb74b35a71a4b68b33c0323350dbdefa2589ef Mon Sep 17 00:00:00 2001 From: Arno Wiest Date: Sun, 25 May 2025 14:13:18 +0200 Subject: [PATCH 6/8] fix: format --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b8a035ae..bde12776 100644 --- a/package.json +++ b/package.json @@ -75,4 +75,4 @@ "volta": { "node": "22.15.1" } -} \ No newline at end of file +} From 97d09157ded2c88b05cf3b82fafa956c9d2a245b Mon Sep 17 00:00:00 2001 From: Arno Wiest Date: Sun, 25 May 2025 21:41:01 +0200 Subject: [PATCH 7/8] fix: lockfile --- package-lock.json | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/package-lock.json b/package-lock.json index f9c9784c..fba0cbdc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,7 +22,6 @@ "@tailwindcss/postcss": "^4.1.7", "@tailwindcss/vite": "^4.1.7", "@types/eslint": "^9.6.0", - "@types/lodash-es": "^4.17.12", "autoprefixer": "^10.4.20", "eslint": "^9.7.0", "eslint-config-prettier": "^10.0.0", @@ -1679,23 +1678,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/lodash": { - "version": "4.17.17", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.17.tgz", - "integrity": "sha512-RRVJ+J3J+WmyOTqnz3PiBLA501eKwXl2noseKOrNo/6+XEHjTAxO4xHvxQB6QuNm+s4WRbn6rSiap8+EA+ykFQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/lodash-es": { - "version": "4.17.12", - "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.12.tgz", - "integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/lodash": "*" - } - }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "8.32.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.32.1.tgz", From 85f628596d96bf26a84d532945b7b3b32ca2a6cf Mon Sep 17 00:00:00 2001 From: Arno Wiest Date: Sat, 7 Jun 2025 10:52:21 +0200 Subject: [PATCH 8/8] chore: refactor to align with select interface --- src/lib/components/Dropdown/Dropdown.svelte | 161 +++++++----------- src/routes/components/dropdown/+page.svelte | 7 + .../components/dropdown/BasicExample.svelte | 15 +- src/routes/components/dropdown/BigList.svelte | 55 +++--- .../components/dropdown/CustomTrigger.svelte | 25 +++ .../components/dropdown/OutlineButton.svelte | 13 +- 6 files changed, 137 insertions(+), 139 deletions(-) create mode 100644 src/routes/components/dropdown/CustomTrigger.svelte diff --git a/src/lib/components/Dropdown/Dropdown.svelte b/src/lib/components/Dropdown/Dropdown.svelte index 92b466b2..ebe975d3 100644 --- a/src/lib/components/Dropdown/Dropdown.svelte +++ b/src/lib/components/Dropdown/Dropdown.svelte @@ -1,120 +1,92 @@ - - + {#snippet child({ props })} - + {#if trigger} + {@render trigger({ props, selectedIcon: value?.icon })} + {:else} + + {/if} {/snippet} - + {#snippet child({ props, wrapperProps, open })} {#if open} @@ -128,28 +100,27 @@ ]} transition:fly={{ y: -30, duration: 250 }} > - {#each options as option (option)} - {@const renderedOption = renderOption(option)} - {@const buttonStyle = renderedOption.disabled + {#each options as option (option.value)} + {@const buttonStyle = option.disabled ? '' : 'transition-all hover:bg-gray-300 dark:hover:bg-gray-800'} diff --git a/src/routes/components/dropdown/+page.svelte b/src/routes/components/dropdown/+page.svelte index c606c7a7..b974d57a 100644 --- a/src/routes/components/dropdown/+page.svelte +++ b/src/routes/components/dropdown/+page.svelte @@ -8,6 +8,8 @@ import outlineButton from './OutlineButton.svelte?raw'; import BigList from './BigList.svelte'; import bigList from './BigList.svelte?raw'; + import CustomTrigger from './CustomTrigger.svelte'; + import customTrigger from './CustomTrigger.svelte?raw'; @@ -23,6 +25,11 @@ code: bigList, component: BigList, }, + { + title: 'Custom Trigger', + code: customTrigger, + component: CustomTrigger, + }, ]} /> diff --git a/src/routes/components/dropdown/BasicExample.svelte b/src/routes/components/dropdown/BasicExample.svelte index 11908546..8c18b95d 100644 --- a/src/routes/components/dropdown/BasicExample.svelte +++ b/src/routes/components/dropdown/BasicExample.svelte @@ -1,16 +1,17 @@ {}} - render={({ label }) => ({ - title: label, - key: label.toLowerCase(), - })} + placeholder="Select a framework" + data={[ + { label: 'Svelte', value: 'svelte', icon: mdiPartyPopper }, + { label: 'React', value: 'react', icon: mdiReact }, + { label: 'Angular', value: 'angular', icon: mdiTrashCan }, + ]} + onChange={() => {}} /> diff --git a/src/routes/components/dropdown/BigList.svelte b/src/routes/components/dropdown/BigList.svelte index 881132d4..6da29f0f 100644 --- a/src/routes/components/dropdown/BigList.svelte +++ b/src/routes/components/dropdown/BigList.svelte @@ -5,34 +5,33 @@ {}} - render={({ label }) => ({ - title: label, - key: label.toLowerCase(), - })} + onChange={() => {}} /> diff --git a/src/routes/components/dropdown/CustomTrigger.svelte b/src/routes/components/dropdown/CustomTrigger.svelte new file mode 100644 index 00000000..829ebaee --- /dev/null +++ b/src/routes/components/dropdown/CustomTrigger.svelte @@ -0,0 +1,25 @@ + + + + + {#snippet trigger({ props, selectedIcon })} + + {/snippet} + + diff --git a/src/routes/components/dropdown/OutlineButton.svelte b/src/routes/components/dropdown/OutlineButton.svelte index 8af92858..afc9132c 100644 --- a/src/routes/components/dropdown/OutlineButton.svelte +++ b/src/routes/components/dropdown/OutlineButton.svelte @@ -5,18 +5,13 @@ {}} - render={({ label, value }) => ({ - title: label, - key: value, - })} />