diff --git a/.changeset/stupid-ads-tap.md b/.changeset/stupid-ads-tap.md
new file mode 100644
index 00000000..625719c8
--- /dev/null
+++ b/.changeset/stupid-ads-tap.md
@@ -0,0 +1,7 @@
+---
+'@ldn-viz/ui': major
+---
+
+CHANGED - the select component is now based on the `svelte-select` library
+ADDED - a new `Tooltip` component allows the display of help tooltips when an icon is hovered over
+ADDED - an `InputWrapper` provides consisten chrome (such as help text or error messages) around input elements
diff --git a/apps/docs/.storybook/preview-head.html b/apps/docs/.storybook/preview-head.html
index 0cf9fa9d..29b5f20a 100644
--- a/apps/docs/.storybook/preview-head.html
+++ b/apps/docs/.storybook/preview-head.html
@@ -1,2 +1,7 @@
-
+
+
+
diff --git a/package-lock.json b/package-lock.json
index 3c5306e0..7f58d552 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,7 +9,8 @@
"packages/*"
],
"dependencies": {
- "@changesets/cli": "^2.26.1"
+ "@changesets/cli": "^2.26.1",
+ "svelte-select": "^5.7.0"
},
"devDependencies": {
"eslint": "^8.0.0",
@@ -17050,6 +17051,15 @@
"node": ">=4.0"
}
},
+ "node_modules/svelte-floating-ui": {
+ "version": "1.5.3",
+ "resolved": "https://registry.npmjs.org/svelte-floating-ui/-/svelte-floating-ui-1.5.3.tgz",
+ "integrity": "sha512-yjLeRQ4SNcICbMabp5S2cXc5ubBd2eua+swfTqqGBeg8ZrUvotZYK8jsRWETl/3RgLQsaZbEYKx8OmLA3wL/yw==",
+ "dependencies": {
+ "@floating-ui/core": "^1.2.4",
+ "@floating-ui/dom": "^1.2.4"
+ }
+ },
"node_modules/svelte-hmr": {
"version": "0.15.3",
"resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.15.3.tgz",
@@ -17165,6 +17175,24 @@
"node": ">=12"
}
},
+ "node_modules/svelte-select": {
+ "version": "5.7.0",
+ "resolved": "https://registry.npmjs.org/svelte-select/-/svelte-select-5.7.0.tgz",
+ "integrity": "sha512-oClK1exjcWDj2817+0djGhK04t5CSZbuP0oh7gz+3dEcn/G+QqRsfI2/dvIyOSHILqNzlj+Ztp2z1pMtE7Wf8Q==",
+ "dependencies": {
+ "@floating-ui/dom": "^1.2.1",
+ "svelte-floating-ui": "1.2.8"
+ }
+ },
+ "node_modules/svelte-select/node_modules/svelte-floating-ui": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/svelte-floating-ui/-/svelte-floating-ui-1.2.8.tgz",
+ "integrity": "sha512-8Ifi5CD2Ui7FX7NjJRmutFtXjrB8T/FMNoS2H8P81t5LHK4I9G4NIs007rLWG/nRl7y+zJUXa3tWuTjYXw/O5A==",
+ "dependencies": {
+ "@floating-ui/core": "^1.1.0",
+ "@floating-ui/dom": "^1.1.0"
+ }
+ },
"node_modules/svelte/node_modules/aria-query": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz",
@@ -19432,7 +19460,8 @@
"@types/d3-dsv": "^3.0.1",
"d3-dsv": "^3.0.1",
"postcss-cli": "^10.1.0",
- "postcss-discard-comments": "^6.0.0"
+ "postcss-discard-comments": "^6.0.0",
+ "svelte-floating-ui": "^1.5.3"
},
"devDependencies": {
"@playwright/test": "^1.28.1",
diff --git a/package.json b/package.json
index 7a925c24..c565b5d5 100644
--- a/package.json
+++ b/package.json
@@ -21,7 +21,8 @@
"packages/*"
],
"dependencies": {
- "@changesets/cli": "^2.26.1"
+ "@changesets/cli": "^2.26.1",
+ "svelte-select": "^5.7.0"
},
"overrides": {
"@rgossiaux/svelte-headlessui": {
diff --git a/packages/themes/ldn-theme.js b/packages/themes/ldn-theme.js
index 310eefef..3e65bc4c 100644
--- a/packages/themes/ldn-theme.js
+++ b/packages/themes/ldn-theme.js
@@ -29,7 +29,7 @@ const config = {
'border-color': ldnColors.core.grey[300],
'&:disabled': {
- 'background-color': ldnColors.core.grey[200]
+ 'background-color': ldnColors.core.grey[100]
}
},
'.form-input, .form-textarea, .form-select, .form-multiselect': {
@@ -38,6 +38,9 @@ const config = {
'border-color': ldnColors.core.blue[600]
}
},
+ '.form-input::placeholder, .form-textarea::placeholder': {
+ color: ldnColors.core.grey[300]
+ },
'.form-checkbox, .form-radio': {
color: ldnColors.core.blue[600],
'&:focus': {
@@ -45,7 +48,8 @@ const config = {
}
},
'.form-label': {
- color: ldnColors.core.grey[700]
+ color: ldnColors.core.grey[700],
+ 'font-weight': '500'
},
'.form-select': {
'background-image': `url("${svgToDataUri(
@@ -55,7 +59,7 @@ const config = {
'.dark': {
'.form-input, .form-textarea, .form-select, .form-multiselect, .form-checkbox, .form-radio':
{
- 'border-color': ldnColors.core.grey[400],
+ 'border-color': ldnColors.core.grey[600],
'background-color': ldnColors.core.grey[600],
color: ldnColors.core.grey[50],
'&:focus': {
@@ -63,11 +67,11 @@ const config = {
},
'&:disabled, &:disabled::placeholder': {
'background-color': ldnColors.core.grey[400],
- color: ldnColors.core.grey[600]
+ color: ldnColors.core.grey[300]
}
},
'.form-input::placeholder, .form-textarea::placeholder': {
- color: ldnColors.core.grey[200]
+ color: ldnColors.core.grey[300]
},
'.form-checkbox, .form-radio': {
color: ldnColors.core.blue[600]
diff --git a/packages/ui/package.json b/packages/ui/package.json
index 666d85d8..6f819c2b 100644
--- a/packages/ui/package.json
+++ b/packages/ui/package.json
@@ -67,7 +67,8 @@
"@types/d3-dsv": "^3.0.1",
"d3-dsv": "^3.0.1",
"postcss-cli": "^10.1.0",
- "postcss-discard-comments": "^6.0.0"
+ "postcss-discard-comments": "^6.0.0",
+ "svelte-floating-ui": "^1.5.3"
},
"overrides": {
"@rgossiaux/svelte-headlessui": {
diff --git a/packages/ui/src/lib/button/Button.svelte b/packages/ui/src/lib/button/Button.svelte
index e3cdd8a9..af259f8a 100644
--- a/packages/ui/src/lib/button/Button.svelte
+++ b/packages/ui/src/lib/button/Button.svelte
@@ -157,6 +157,8 @@
on:touchcancel
on:mouseenter
on:mouseleave
+ role="button"
+ tabindex="0"
>
diff --git a/packages/ui/src/lib/index.js b/packages/ui/src/lib/index.js
index 6d7877c1..cc40edca 100644
--- a/packages/ui/src/lib/index.js
+++ b/packages/ui/src/lib/index.js
@@ -1,40 +1,33 @@
// Reexport your entry components here
export { default as Button } from './button/Button.svelte';
-
export { default as Checkbox } from './checkBox/Checkbox.svelte';
export { default as CheckboxGroup } from './checkBox/CheckboxGroup.svelte';
-
export { default as DataDownloadButton } from './dataDownloadButton/DataDownloadButton.svelte';
+export { default as Header } from './header/Header.svelte';
+export { default as HeaderItem } from './header/HeaderItem.svelte';
+export { default as HeaderRight } from './header/HeaderRight.svelte';
+export { default as HeaderTitle } from './header/HeaderTitle.svelte';
+export { default as NavLink } from './header/NavLink.svelte';
+export { default as NavLinks } from './header/NavLinks.svelte';
export { default as ImageDownloadButton } from './imageDownloadButton/ImageDownloadButton.svelte';
export { default as LogoByCIU } from './logos/LogoByCIU.svelte';
export { default as LogoCIU } from './logos/LogoCIU.svelte';
export { default as LogoLOTI } from './logos/LogoLOTI.svelte';
export { default as LogoMayor } from './logos/LogoMayor.svelte';
-
export { default as Modal } from './modal/Modal.svelte';
-export { default as Header } from './header/Header.svelte';
-export { default as HeaderItem } from './header/HeaderItem.svelte';
-export { default as HeaderRight } from './header/HeaderRight.svelte';
-export { default as HeaderTitle } from './header/HeaderTitle.svelte';
-export { default as NavLink } from './header/NavLink.svelte';
-export { default as NavLinks } from './header/NavLinks.svelte';
-
export { default as PlacardButton } from './placardButton/PlacardButton.svelte';
export { default as RadioButton } from './radioButton/RadioButton.svelte';
export { default as RadioButtonGroup } from './radioButton/RadioButtonGroup.svelte';
-
export { default as RadioButtonGroupSolid } from './radioButtonSolid/RadioButtonGroupSolid.svelte';
export { default as RadioButtonSolid } from './radioButtonSolid/RadioButtonSolid.svelte';
-
export { default as Select } from './select/Select.svelte';
export { default as Spinner } from './spinners/Spinner.svelte';
export { default as TabbedSidebar } from './tabbedSidebar/TabbedSidebar.svelte';
export { default as TabbedSidebarTabLabel } from './tabbedSidebar/TabbedSidebarTabLabel.svelte';
export { default as TabbedSidebarTabList } from './tabbedSidebar/TabbedSidebarTabList.svelte';
export { default as TabbedSidebarWrapper } from './tabbedSidebar/TabbedSidebarWrapper.svelte';
-
export { default as TabLabel } from './tabs/TabLabel.svelte';
export { default as TabList } from './tabs/TabList.svelte';
diff --git a/packages/ui/src/lib/input/Input.stories.svelte b/packages/ui/src/lib/input/Input.stories.svelte
new file mode 100644
index 00000000..77e4b444
--- /dev/null
+++ b/packages/ui/src/lib/input/Input.stories.svelte
@@ -0,0 +1,83 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/ui/src/lib/input/Input.svelte b/packages/ui/src/lib/input/Input.svelte
new file mode 100644
index 00000000..6b3ca7ea
--- /dev/null
+++ b/packages/ui/src/lib/input/Input.svelte
@@ -0,0 +1,25 @@
+
+
+
+
+
diff --git a/packages/ui/src/lib/input/InputWrapper.svelte b/packages/ui/src/lib/input/InputWrapper.svelte
new file mode 100644
index 00000000..189af813
--- /dev/null
+++ b/packages/ui/src/lib/input/InputWrapper.svelte
@@ -0,0 +1,65 @@
+
+
+
+
+ {#if label}
+
+ {label}{#if optional} (optional){/if}
+
+ {/if}
+
+ {#if hint}
+
+ {hintTooltipContent}
+
+ {/if}
+
+
+
+
+ {#if description && !errorMessage}
+
{description}
+ {:else if errorMessage}
+
{errorMessage}
+ {/if}
+
+
diff --git a/packages/ui/src/lib/select/Introduction.mdx b/packages/ui/src/lib/select/Introduction.mdx
index 6fbb376f..34c6b301 100644
--- a/packages/ui/src/lib/select/Introduction.mdx
+++ b/packages/ui/src/lib/select/Introduction.mdx
@@ -6,6 +6,5 @@ import { Meta } from '@storybook/blocks';
The `Select` component allows users to select an option form a drop-down list of alternatives.
-It may [have a label](./?path=/story/ui-select--with-label),
-[have an initially value/initially selected item](./?path=/story/ui-select--with-initial-value) or
-[be disabled](./?path=/story/ui-select--disabled).
+Our select element is a wrapper around ['Svelte Select'](https://github.com/rob-balfre/svelte-select)
+Check the documentation for advanced usage and a full list of props, events, slots etc.
diff --git a/packages/ui/src/lib/select/Select.stories.svelte b/packages/ui/src/lib/select/Select.stories.svelte
index 595210e8..2089de91 100644
--- a/packages/ui/src/lib/select/Select.stories.svelte
+++ b/packages/ui/src/lib/select/Select.stories.svelte
@@ -1,14 +1,15 @@
-
@@ -18,12 +19,122 @@
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ console.log('Selection changed!')}
+ />
+
+
+ Value is: {JSON.stringify(value)}
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
diff --git a/packages/ui/src/lib/select/Select.svelte b/packages/ui/src/lib/select/Select.svelte
index 2b8c2539..9af74698 100644
--- a/packages/ui/src/lib/select/Select.svelte
+++ b/packages/ui/src/lib/select/Select.svelte
@@ -1,93 +1,145 @@
- dispatch('change', ev.detail)} {disabled} class="relative">
- {#if label !== undefined}
-
- classNames(
- disabled
- ? 'text-gray-700 dark:text-core-grey-400'
- : 'text-gray-700 dark:text-core-grey-50',
- 'block text-sm font-medium'
- )}
- >{label}
-
- {/if}
-
-
- classNames(
- disabled
- ? 'bg-gray-200 dark:bg-core-grey-600 dark:text-core-grey-400'
- : 'bg-white dark:bg-core-grey-600 dark:text-core-grey-50',
- 'relative w-full cursor-default border border-gray-300 dark:border-gray-700 py-2 pl-3 pr-10 text-left shadow-sm focus:border-core-blue-500 focus:outline-none focus:ring-1 focus:ring-core-blue-500 sm:text-sm'
- )}
- >
-
- {!(value === undefined || value === null) && !disabled && options.length > 0
- ? options.filter((d) => d.id === value)[0]?.label
- : 'Select option'}
-
-
-
-
-
-
+
+
+
-
- {#each options as option (option.id)}
-
- classNames(
- active ? 'text-white bg-core-blue-600' : 'text-gray-900 dark:text-core-grey-50',
- 'relative cursor-default select-none py-2 pl-3 pr-9'
- )}
- let:selected
- >
- {#if selected}
-
-
-
- {/if}
-
- {option.label}
-
-
- {/each}
-
-
+
+
+{#if !!true}
+
+{/if}
diff --git a/packages/ui/src/lib/tooltip/Tooltip.stories.svelte b/packages/ui/src/lib/tooltip/Tooltip.stories.svelte
new file mode 100644
index 00000000..e9cf8d46
--- /dev/null
+++ b/packages/ui/src/lib/tooltip/Tooltip.stories.svelte
@@ -0,0 +1,31 @@
+
+
+
+
+
+ This is some text
+
+
+
+ This is some text
+
+
+
+
+ I have a diffent icon
+ But I still work the same
+
+
diff --git a/packages/ui/src/lib/tooltip/Tooltip.svelte b/packages/ui/src/lib/tooltip/Tooltip.svelte
new file mode 100644
index 00000000..da8b8f4d
--- /dev/null
+++ b/packages/ui/src/lib/tooltip/Tooltip.svelte
@@ -0,0 +1,76 @@
+
+
+
{
+ showTooltip = true;
+ floatingRef(element);
+ }}
+ on:mouseleave|stopPropagation={() => (showTooltip = false)}
+ use:floatingRef
+ role="tooltip"
+>
+
+ {hintLabel}
+
+
+
+
+{#if showTooltip}
+
+{/if}
diff --git a/packages/ui/src/lib/tooltip/tooltip.ts b/packages/ui/src/lib/tooltip/tooltip.ts
new file mode 100644
index 00000000..48394628
--- /dev/null
+++ b/packages/ui/src/lib/tooltip/tooltip.ts
@@ -0,0 +1,6 @@
+import { createFloatingActions } from 'svelte-floating-ui';
+
+export const [floatingRef, floatingContent] = createFloatingActions({
+ strategy: 'absolute',
+ placement: 'top'
+});