Skip to content

Commit

Permalink
input-tag
Browse files Browse the repository at this point in the history
  • Loading branch information
tborychowski committed Sep 24, 2023
1 parent 0fc3fe2 commit 2f16a22
Show file tree
Hide file tree
Showing 9 changed files with 294 additions and 146 deletions.
15 changes: 12 additions & 3 deletions docs-src/components/input/input-tag/InputTag.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,13 @@
<InputTag bind:value="{val}" />
<p>Input value: {val}</p>

<InputTag
value="tag1, anotherOne, long-tag-name"
{tags}
on:input="{oninput}" />

<h3>Disabled</h3>
<InputTag disabled value="disabled value" on:input="{oninput}" />
<InputTag disabled value="disabled" />


<h3>Label on the left</h3>
Expand Down Expand Up @@ -54,7 +59,11 @@ function onChange (e) {
&lt;/script>
`;
let val = '';
let val = 'tag1, tag2';
const tags = [
{ text: 'Tag1', color: 'blue' },
{ text: 'AnotherOne', color: 'green' },
{ text: 'Long-name-tag-3' },
];
</script>
1 change: 0 additions & 1 deletion docs-src/components/tag/Tag.css

This file was deleted.

2 changes: 1 addition & 1 deletion docs/docs.css

Large diffs are not rendered by default.

204 changes: 102 additions & 102 deletions docs/docs.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/ui.css

Large diffs are not rendered by default.

66 changes: 57 additions & 9 deletions src/input/input-tag/InputTag.css
Original file line number Diff line number Diff line change
@@ -1,12 +1,60 @@
.input-search input {
padding-left: calc(2rem + 6px);
padding-right: 2rem;
appearance: none;
-webkit-appearance: none;
.input-tag .input-row {
min-height: calc(var(--ui-button-height) - 2px);
padding: 0.3rem 0.3rem calc(0.3rem - 1px);
align-items: flex-start;
justify-content: flex-start;
gap: 0.2rem;
flex-wrap: wrap;
}
::-webkit-search-cancel-button { display: none; }

.input-search .input-row>.icon { top: 1px; }
.input-tag .input-row > .button { margin-left: auto; }
.input-tag .input-row > .icon { margin-top: 1px; }

.input-search-button { display: none; }
.input-search-button.visible { display: inline-flex; }
.input-tag .input-row > .button,
.input-tag .input-row > .icon { position: static; flex-shrink: 0; }


.input-tag-list {
position: absolute;
z-index: var(--ui-z-index-popup);
overflow-y: auto;
overscroll-behavior-y: contain;
padding: 1rem;
min-height: 0;
max-height: 26rem;
-webkit-user-select: none;
user-select: none;
transform: translateZ(1px);
width: min-content;
color: var(--ui-color-text);
border: var(--ui-popup-border);
border-radius: calc(var(--ui-border-radius) + 0.2rem);
background: var(--ui-popup-background);
box-shadow: var(--ui-shadow-fancy);
}

.input-tag-list-add-row {
display: flex;
align-items: center;
gap: 0.5rem;
margin-top: 1rem;
padding-top: 1rem;
border-top: var(--ui-popup-border);
}
.input-tag-list-add-row .input { width: 100px; flex: 1; }

.input-tag-list-tags {
display: flex;
flex-flow: row wrap;
gap: 0.5rem;
width: 100%;
}


@supports ((-webkit-backdrop-filter: none) or (backdrop-filter: none)) {
.input-tag-list {
background-color: var(--ui-color-background-semi);
-webkit-backdrop-filter: blur(30px);
backdrop-filter: blur(30px);
}
}
145 changes: 118 additions & 27 deletions src/input/input-tag/InputTag.svelte
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
<div
class="input input-search {className}"
class="input input-tag {className}"
class:has-error="{error}"
class:has-value="{value !== ''}"
class:label-on-the-left="{labelOnTheLeft === true || labelOnTheLeft === 'true'}"
{title}
bind:this="{element}">

<Label {label} {disabled} for="{_id}"/>
Expand All @@ -13,68 +14,158 @@

<div class="input-row">
<Icon name="tag"/>
{#each _value as tag}
<Tag icon="close">{tag}</Tag>
{/each}
<Button link
icon="add"
class="input-add-button"
{disabled}
on:click="{toggle}"/>

<input
autocomplete="off"
type="text"
{...props}
{name}
{disabled}
id="{_id}"
aria-invalid="{error}"
aria-errormessage="{error ? errorMessageId : undefined}"
aria-required="{required}"
bind:this="{inputElement}"
type="hidden"
bind:value="{value}"
on:input
on:keydown="{onkeydown}"
on:change
on:focus
on:blur>

<Button link
icon="close"
class="input-search-button {value !== '' && !disabled ? 'visible' : ''}"
on:click="{clear}"/>
bind:this="{inputElement}"/>
</div>
</div>
</div>

{#if opened}
<div
id="input-tag-list-{listId}"
class="input-tag-list {opened ? '' : 'hidden'}"
role="listbox"
bind:this="{listElement}">
<div class="input-tag-list-tags">
{#each tags as tag}
<Tag icon="add">{tag.text}</Tag>
{/each}
</div>
<form class="input-tag-list-add-row" on:submit|preventDefault="{addTag}">
<InputText bind:value="{newTagName}"/>
<Button submit link icon="add"/>
</form>
</div>
{/if}

<script>
import { pluck, guid } from '../../utils';
import { InputText } from '../input-text';
import { Button } from '../../button';
import { Tag } from '../../tag';
import { guid, alignItem, FOCUSABLE_SELECTOR } from '../../utils';
import { Icon } from '../../icon';
import { Info } from '../../info-bar';
import { InputError } from '../input-error';
import { Label } from '../label';
$:props = pluck($$props, ['title', 'name', 'placeholder']);
let className = '';
export { className as class };
export let id = '';
export let required = undefined;
export let name = '';
export let disabled = false;
export let value = '';
export let title = false;
export let label = '';
export let error = undefined;
export let info = undefined;
export let labelOnTheLeft = false;
export let value = '';
export let tags = [];
export let element = undefined;
export let inputElement = undefined;
export let listElement = undefined;
const listId = guid();
const errorMessageId = guid();
let opened = false;
let newTagName = '';
$:_id = id || name || guid();
$:_value = value.split(/[, ;]/).map(tag => tag.trim()).filter(tag => tag !== '');
const errorMessageId = guid();
function clear () {
value = '';
function toggle () {
if (opened) close();
else open();
}
function open (e) {
if (opened) return;
opened = true;
requestAnimationFrame(() => {
if (listElement.parentElement !== document.body) {
document.body.appendChild(listElement);
}
addEventListeners();
alignDropdown(e);
listElement.querySelector(FOCUSABLE_SELECTOR).focus();
});
}
function onkeydown (event) {
if (event.key === 'Escape') clear();
function close () {
if (!opened) return;
removeEventListeners();
opened = false;
}
function addTag () {
const newTags = newTagName
.split(/[, ;]/)
.map(tag => tag.trim())
.filter(tag => tag !== '')
.map(tag => ({ text: tag }));
tags = [...tags, ...newTags];
newTagName = '';
}
function alignDropdown () {
alignItem({
element: listElement,
target: element,
setMinWidthToTarget: true,
});
}
function onResize () {
if (!opened) return;
return close();
}
function onViewportResize () {
if (!opened) return;
alignDropdown();
}
function onDocumentClick (e) {
const notEl = element && !element.contains(e.target);
const notList = listElement && !listElement.contains(e.target);
if (open && notEl && notList) close();
}
function addEventListeners () {
window.addEventListener('resize', onResize);
document.addEventListener('click', onDocumentClick, true);
window.visualViewport.addEventListener('resize', onViewportResize);
}
function removeEventListeners () {
window.removeEventListener('resize', onResize);
document.removeEventListener('click', onDocumentClick, true);
window.visualViewport.removeEventListener('resize', onViewportResize);
}
</script>
3 changes: 2 additions & 1 deletion src/tag/Tag.css
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@
color: var(--ui-color-text);
}

.ui-tag .icon { width: 1.2rem; height: 1.2rem; }
.ui-tag .icon { width: 1.2rem; height: 1.2rem; margin-left: -4px; }

.ui-tag:focus-visible {
border-color: var(--ui-color-accent);
box-shadow: var(--ui-shadow-focus);
outline: 1px solid transparent;
}
.ui-tag .ui-tag-label { line-height: 1.2rem; }

.ui-tag.dark { color: #fff; }

Expand Down
2 changes: 1 addition & 1 deletion src/tag/Tag.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
{#if icon}
<Icon name="{icon}"/>
{/if}
<slot/>
<div class="ui-tag-label"><slot/></div>
</div>

<script>
Expand Down

0 comments on commit 2f16a22

Please sign in to comment.