Skip to content

Commit

Permalink
Merge pull request #179 from perfect-things/multiselect
Browse files Browse the repository at this point in the history
multiselect
  • Loading branch information
tborychowski authored Jan 5, 2024
2 parents e43a2ce + 8370aa7 commit 22f8522
Show file tree
Hide file tree
Showing 17 changed files with 449 additions and 219 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
Changelog
=========

## v9.4.0 *(2024-01-04)*
- Add `multiselect` option to the `Combobox`.


## v9.3.4, v9.3.3 *(2023-12-25)*
- Fix `InputDate` when picker was not in sync with the input value.
- Better dropdown alignment for `Popover` and `Menu` onScroll (should work if scrolling other elements beside the `<body>`).
Expand Down
34 changes: 34 additions & 0 deletions docs-src/code-example/JsonBox.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<pre><code class="language-json">{@html code}</code></pre>

<script>
import { afterUpdate } from 'svelte';
export let value ='';
let code ='';
afterUpdate(() => {
requestAnimationFrame(update);
});
function update () {
if (typeof value !== 'string') value = stringify(value);
code = window.Prism.highlight(value, window.Prism.languages.json, 'json');
}
function stringify (json) {
if (!json) return '';
let s = JSON.stringify(json);
s = s.replace(/([:,])/g, '$1 ');
if (s.match(/^{/)) s = s.replace(/{/g, '{ ');
else {
if (s.match(/}/)) s = s.replace(/\]/g, '\n]');
s = s.replace(/{/g, '\n { ');
}
s = s.replace(/}/g, ' }');
return s;
}
</script>
1 change: 1 addition & 0 deletions docs-src/code-example/index.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { default as CodeExample } from './CodeExample.svelte';
export { default as CodeBox } from './CodeBox.svelte';
export { default as JsonBox } from './JsonBox.svelte';
84 changes: 63 additions & 21 deletions docs-src/components/input/combobox/Combobox.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
bind:value="{itemValue}" />

<h4>Selected value: </h4>
<code>{JSON.stringify(itemValue || {})}</code>
<JsonBox value="{itemValue}" />


<h3>Disabled</h3>
Expand All @@ -17,19 +17,28 @@
<Combobox
{items}
placeholder="Type to filter"
allowNew="true"
allowNew
bind:value="{itemValue}" />


<h3>Show on focus</h3>
<Combobox showOnFocus="true" {items} bind:value="{itemValue}" />

<h3>Simpler data (no ID, just 'name')</h3>
<Combobox items="{dataSimple}" placeholder="Type to filter"
<Combobox items="{dataSimpler}" placeholder="Type to filter"
bind:value="{valueSimpler}" />

<h4>Selected value: </h4>
<JsonBox value="{valueSimpler}" />


<h3>Simple data (just an array of strings)</h3>
<Combobox items="{dataSimple}" placeholder="Type to filter" allowNew
bind:value="{valueSimple}" />

<h3>Simplest data (just an array of strings)</h3>
<Combobox items="{dataSimplest}" placeholder="Type to filter" allowNew="true"
bind:value="{valueSimplest}" />
<h4>Selected value: </h4>
<JsonBox value="{valueSimple}" />


<h3>Label</h3>
<Combobox {items} label="Combobox label" />
Expand All @@ -41,7 +50,31 @@
<Combobox {items} label="Combobox label" error="You picked the wrong side!" />

<h3>Label on the left</h3>
<Combobox {items} label="Label is on the left" labelOnTheLeft="true"/>
<Combobox {items} label="Label is on the left" labelOnTheLeft/>



<h2>Multiselect</h2>
<p>This adds checkboxes to the list items, but it disables the auto-lookup functionality,<br>as the input value string becomes a comma-separated list of selected items' names.</p>

<h3>Simple data</h3>
<Combobox
items="{dataSimple}"
multiselect
placeholder="Type to filter"
bind:value="{multiselectSimpleValue}" />
<h4>Selected value: </h4>
<JsonBox value="{multiselectSimpleValue}" />


<h3>Complex data</h3>
<Combobox
{items}
multiselect
placeholder="Type to filter"
bind:value="{multiselectValue}" />
<h4>Selected value: </h4>
<JsonBox value="{multiselectValue}" />



Expand All @@ -54,28 +87,36 @@
<script>
import { Combobox } from '../../../../src';
import { API } from '../../../api-table';
import { CodeExample } from '../../../code-example';
import { CodeExample, JsonBox } from '../../../code-example';
const apiProps = [
{ name: 'allowNew', type: ['true', 'false'], default: 'false', description: 'Whether to allow arbitrary values (that don\'t exist in the list).' },
{ name: 'allowNew', description: 'Whether to allow arbitrary values (that don\'t exist in the list).' },
{ name: 'class', type: 'string', description: 'Additional css class name to be added to the component.' },
{ name: 'clearOnEsc', type: ['true', 'false'], default: 'false', description: 'If <i>true</i> - the combobox will be cleared when Escape is pressed.' },
{ name: 'clearOnEsc', description: 'If present - the combobox will be cleared when Escape is pressed.' },
{ name: 'disabled', description: 'Make the combobox disabled.' },
{ name: 'error', type: 'string', description: 'Error message to show above the combobox.' },
{ name: 'hideOnResize', type: ['true', 'false'], default: 'false', description: 'If <i>true</i> - resizing the window will close the popup.' },
{ name: 'hideOnResize', description: 'If present - resizing the window will close the popup.' },
{ name: 'id', type: 'string', description: 'Assign ID to the underlying input.' },
{ name: 'info', type: 'string', description: 'Show info message above the combobox.' },
{ name: 'items', type: 'array', required: true, description: 'An array of strings or objects in the following format: <code>&lbrace; name: string, id?: string | number, group?: string &rbrace;</code>(<i>name</i> should be unique, or - if <i>id</i> is present - <i>id</i> should be unique).' },
{ name: 'label', type: 'string', description: 'Label for the combobox.' },
{ name: 'labelOnTheLeft', type: ['true', 'false'], default: 'false', description: 'Put label to the left of the input (instead of at the top). Usually in longer forms, to align labels and inputs, hence input also gets <em>width: 100%</em>, as it will be constraint by the form container.' },
{ name: 'labelOnTheLeft', description: 'Put label to the left of the input (instead of at the top). Usually in longer forms, to align labels and inputs, hence input also gets <em>width: 100%</em>, as it will be constraint by the form container.' },
{ name: 'name', type: 'string', description: 'Assign title to the underlying input.' },
{ name: 'multiselect', description: 'This changes the control to a multiselect. The following changes will apply:<ul>' +
'<li>dropdown items will receive checkboxes,' +
'<li>the input textbox will become read-only,' +
'<li>text input will loose the auto-lookup functionality,' +
'<li>the control will only allow to change the value by clicking on items (or check them using the `Space` key),' +
'<li>the value will become an array,' +
'<li>arguments `allowNew`, `clearOnEsc` and `placeholder` will have no effect.' +
'</ul>'
},
{ name: 'placeholder', type: 'string', description: 'Shows placeholder text.' },
{ name: 'required', description: 'Mark the combobox as <i>aria-required</i>.' },
{ name: 'showAllInitially', type: ['true', 'false'], default: 'true', description: 'When the combobox has a value - the list in the poput is filtered by the combobox value.<br>If this option is set to true (default) - when user navigates to the combobox (with a value)<br> or clicks such an combobox - the poput initially will show all items unfiltered, and only once<br> user starts typing - the list will be filtered again.<br> If this value is set to <i>"false"</i> (or boolean <i>false</i>) - the list will always be filtered. ' },
{ name: 'showOnFocus', type: ['true', 'false'], default: 'false', description: 'If <i>true</i> - the popup will be automatically open when the combobox gets focus (as opposed to, when the user starts typing).' },
{ name: 'showOnFocus', description: 'If present - the popup will be automatically open when the combobox gets focus (as opposed to, when the user starts typing).' },
{ name: 'title', type: 'string', description: 'Assign title to the underlying input.' },
{ name: 'value', type: ['string', 'number'], description: 'Initial value of the combobox.' },
{ name: 'value', type: ['string', 'number', 'object', 'array'], description: 'Value of the combobox.<br>If combobox is <em>multiselect</em>, the value will be an array. ' },
{ name: 'bind:element', type: 'element', description: 'Exposes the HTML element of the component.' },
{ name: 'bind:inputElement', type: 'element', description: 'Exposes the HTML element of the underlying input.' },
{ name: 'on:change', type: 'function', description: 'Triggered when the value changes.' },
Expand Down Expand Up @@ -128,9 +169,9 @@ const items = [
{ id: 17, name: 'Lambda', group: 'Group 3' },
];
let itemValue = items[1];
let multiselectValue = [items[0], items[1]];
const dataSimple = [
const dataSimpler = [
{ name: 'Alpha', group: 'Group 1' },
{ name: 'Beta', group: 'Group 1' },
{ name: 'Gamma', group: 'Group 1' },
Expand All @@ -150,9 +191,9 @@ const dataSimple = [
{ name: 'Delta' },
{ name: 'Epsilon' },
];
let valueSimple = dataSimple[3];
let valueSimpler = dataSimpler[3];
const dataSimplest = [
const dataSimple = [
'Alpha',
'Beta',
'Gamma',
Expand All @@ -162,15 +203,16 @@ const dataSimplest = [
'Eta',
'Theta',
'Iota',
'Iota',
'Kappa',
'Lambda is the last item in this list',
];
let valueSimplest = 'Gamma';
let valueSimple = 'Gamma';
let multiselectSimpleValue = [dataSimple[0], dataSimple[1]];
function onChange (e) {
const { value, oldValue } = e.detail;
console.log({ value, oldValue });
}
</script>
4 changes: 2 additions & 2 deletions docs-src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
<meta charset="UTF-8">
<title>PerfectThings UI</title>
<meta name="viewport" content="initial-scale=1.0">
<link rel="stylesheet" href="ui.css?v=15">
<link rel="stylesheet" href="docs.css?v=15">
<link rel="stylesheet" href="ui.css?v=16">
<link rel="stylesheet" href="docs.css?v=16">
<link rel="icon" type="image/svg+xml" href="favicon.svg">
</head>
<body tabindex="0">
Expand Down
4 changes: 4 additions & 0 deletions docs-src/pages/changelog.svelte
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
<h1>Changelog</h1>
<h2>v9.4.0 <em>(2024-01-04)</em></h2>
<ul>
<li>Add <code>multiselect</code> option to the <code>Combobox</code>.</li>
</ul>
<h2>v9.3.4, v9.3.3 <em>(2023-12-25)</em></h2>
<ul>
<li>Fix <code>InputDate</code> when picker was not in sync with the input value.</li>
Expand Down
244 changes: 123 additions & 121 deletions docs/docs.js

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions docs/docs.js.map

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
<meta charset="UTF-8">
<title>PerfectThings UI</title>
<meta name="viewport" content="initial-scale=1.0">
<link rel="stylesheet" href="ui.css?v=15">
<link rel="stylesheet" href="docs.css?v=15">
<link rel="stylesheet" href="ui.css?v=16">
<link rel="stylesheet" href="docs.css?v=16">
<link rel="icon" type="image/svg+xml" href="favicon.svg">
</head>
<body tabindex="0">
Expand Down
2 changes: 1 addition & 1 deletion docs/ui.css

Large diffs are not rendered by default.

25 changes: 16 additions & 9 deletions src/input/combobox/Combobox.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
.combobox .input-inner { position: relative; }

.combobox input { padding-right: 36px; }
.multiselect input { text-overflow: ellipsis; }

.combobox-button:focus { box-shadow: none; }

Expand All @@ -23,8 +24,8 @@
box-shadow: var(--ui-shadow-fancy);
}

.combobox-list:empty { padding: 0; box-shadow: none; border: none; }
.combobox-list:not(:empty) { min-height: 2rem; }
.combobox-list.empty { padding: 0; box-shadow: none; border: none; }
.combobox-list:not(.empty) { min-height: 2rem; }
.combobox-list.hidden { display: none; }

.combobox-list-header,
Expand Down Expand Up @@ -63,22 +64,28 @@
touch-action: manipulation;
}

.combobox-list-item.in-group {
padding-left: 2rem;
.combobox-list-item svg { margin-right: 0.5rem; }

.combobox-list:not(.multiselect) .combobox-list-item.in-group { padding-left: 2rem; }


.mobile .combobox-list-item { transition: background-color 0.3s ease-out; }
.mobile .combobox-list-item.blinking {
transition: background-color 0.1s;
background-color: var(--ui-color-highlight-1);
}

.combobox-list-item.selected {

.desktop .combobox-list-item.selected {
background-color: var(--ui-color-highlight-1);
outline: 1px solid transparent;
}
.combobox-list-item:hover {
.desktop .combobox-list-item:hover {
background-color: var(--ui-color-highlight);
outline: 1px solid transparent;
}

.combobox-list-item b {
color: var(--ui-color-accent);
}
.combobox-list-item b { color: var(--ui-color-accent); }



Expand Down
Loading

0 comments on commit 22f8522

Please sign in to comment.