mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-16 13:21:57 +00:00
UBERF-5394: Create component for new search input (#4777)
* UBERF-5394: Create component for new search input Signed-off-by: Eduard Aksamitov <e@euaaaio.ru> * chore(SearchPicker): cleanup Signed-off-by: Eduard Aksamitov <e@euaaaio.ru> * fix(SearchPickerItem): truncate text Signed-off-by: Eduard Aksamitov <e@euaaaio.ru> * chore(SearchPicker): flex width Signed-off-by: Eduard Aksamitov <e@euaaaio.ru> * fix: better styles & light theme Signed-off-by: Eduard Aksamitov <e@euaaaio.ru> * chore(SearchPicker): move borders and outlines to `rem` Signed-off-by: Eduard Aksamitov <e@euaaaio.ru> * chore: cleanup Signed-off-by: Eduard Aksamitov <e@euaaaio.ru> * feat: better styles, removable badges via `Backspace` Signed-off-by: Eduard Aksamitov <e@euaaaio.ru> * chore: cleanup Signed-off-by: Eduard Aksamitov <e@euaaaio.ru> * refactor(Chip): use `ButtonIcon` Signed-off-by: Eduard Aksamitov <e@euaaaio.ru> * chore: format Signed-off-by: Eduard Aksamitov <e@euaaaio.ru> --------- Signed-off-by: Eduard Aksamitov <e@euaaaio.ru>
This commit is contained in:
parent
58d39f0cd6
commit
7224bc625a
@ -7,7 +7,9 @@
|
||||
* {
|
||||
--global-accent-IconColor: #6796FF;
|
||||
--global-on-accent-TextColor: #FFFFFF;
|
||||
--global-focus-inset-BorderColor: #0D121C;
|
||||
|
||||
--global-ui-hover-OverlayColor: #15307226;
|
||||
--global-ui-active-OverlayColor: #15307233;
|
||||
|
||||
--button-accent-LabelColor: #fff;
|
||||
--button-disabled-LabelColor: #8b97ad;
|
||||
@ -22,6 +24,8 @@
|
||||
--button-negative-BorderColor: #d1d5de26;
|
||||
--button-negative-hover-BackgroundColor: #e34748;
|
||||
--button-negative-active-BackgroundColor: #c42a32;
|
||||
|
||||
--tag-on-accent-PorpoiseText: #FFFFFF;
|
||||
}
|
||||
|
||||
/* Dark Theme */
|
||||
@ -29,6 +33,7 @@
|
||||
--global-ui-BackgroundColor: #A5BDFF0D;
|
||||
--global-ui-BorderColor: #A5BDFF1A;
|
||||
--global-ui-hover-BackgroundColor: #A5BDFF1A;
|
||||
--global-ui-active-BackgroundColor: #A5BDFF26;
|
||||
--global-ui-highlight-BackgroundColor: #A5BDFF0D;
|
||||
--global-ui-hover-highlight-BackgroundColor: #A5BDFF26;
|
||||
--global-surface-01-BackgroundColor: #131925;
|
||||
@ -49,10 +54,12 @@
|
||||
--global-accent-TextColor: #4D7FF5;
|
||||
--global-error-TextColor: #FF6359;
|
||||
--global-focus-BorderColor: #2A59D6;
|
||||
--global-focus-inset-BorderColor: #0D121C;
|
||||
--global-popover-ShadowColor: #0E131E59;
|
||||
--global-modal-ShadowColor: #0E131E73;
|
||||
--global-higlight-Color: #F76E53;
|
||||
--global-accent-SkyText: #B9D1F5;
|
||||
--global-accent-BackgroundColor: #204DC8;
|
||||
|
||||
--tag-on-subtle-PorpoiseText: #F2F4F6;
|
||||
--tag-subtle-PorpoiseBackground: #343F49;
|
||||
@ -91,6 +98,7 @@
|
||||
--global-ui-BackgroundColor: #1530720D;
|
||||
--global-ui-BorderColor: #1530721A;
|
||||
--global-ui-hover-BackgroundColor: #1530721A;
|
||||
--global-ui-active-BackgroundColor: #A5BDFF40;
|
||||
--global-ui-highlight-BackgroundColor: #A5BDFF26;
|
||||
--global-ui-hover-highlight-BackgroundColor: #A5BDFF40;
|
||||
--global-surface-01-BackgroundColor: #F8F9FA;
|
||||
@ -111,10 +119,12 @@
|
||||
--global-accent-TextColor: #3566E2;
|
||||
--global-error-TextColor: #A40A1B;
|
||||
--global-focus-BorderColor: #204DC8;
|
||||
--global-focus-inset-BorderColor: #FFFFFF;
|
||||
--global-popover-ShadowColor: #0E131E1F;
|
||||
--global-modal-ShadowColor: #0E131E14;
|
||||
--global-higlight-Color: #F76E53;
|
||||
--global-accent-SkyText:#B9D1F5;
|
||||
--global-accent-BackgroundColor: #3566E2;
|
||||
|
||||
--tag-on-subtle-PorpoiseText: #293139;
|
||||
--tag-subtle-PorpoiseBackground: #C8D1D9;
|
||||
|
@ -29,7 +29,7 @@
|
||||
export let iconSize: IconSize | undefined = undefined
|
||||
export let iconProps: any | undefined = undefined
|
||||
export let kind: 'primary' | 'secondary' | 'tertiary' | 'negative'
|
||||
export let size: 'large' | 'medium' | 'small' | 'extra-small'
|
||||
export let size: 'large' | 'medium' | 'small' | 'extra-small' | 'min'
|
||||
export let disabled: boolean = false
|
||||
export let loading: boolean = false
|
||||
export let pressed: boolean = false
|
||||
@ -48,6 +48,10 @@
|
||||
actualIconSize = 'medium'
|
||||
}
|
||||
|
||||
export function focus () {
|
||||
element?.focus()
|
||||
}
|
||||
|
||||
// Focusable control with index
|
||||
export let focusIndex = -1
|
||||
const { idx, focusManager } = registerFocus(focusIndex, {
|
||||
@ -83,6 +87,7 @@
|
||||
disabled={loading || disabled}
|
||||
use:tp={tooltip}
|
||||
on:click
|
||||
on:keydown
|
||||
>
|
||||
{#if loading}
|
||||
<div class="icon animate"><Spinner size={type === 'type-button' && !hasMenu ? 'medium' : 'small'} /></div>
|
||||
@ -172,6 +177,11 @@
|
||||
width: var(--global-extra-small-Size);
|
||||
}
|
||||
}
|
||||
&.min {
|
||||
height: var(--global-min-Size);
|
||||
border: 0;
|
||||
border-radius: var(--min-BorderRadius);
|
||||
}
|
||||
&.type-button-icon .icon,
|
||||
&.menu .icon {
|
||||
width: var(--spacing-2);
|
||||
|
@ -19,7 +19,7 @@
|
||||
import ButtonBase from './ButtonBase.svelte'
|
||||
|
||||
export let kind: 'primary' | 'secondary' | 'tertiary' | 'negative' = 'secondary'
|
||||
export let size: 'large' | 'medium' | 'small' | 'extra-small' = 'large'
|
||||
export let size: 'large' | 'medium' | 'small' | 'extra-small' | 'min' = 'large'
|
||||
export let icon: Asset | AnySvelteComponent | ComponentType
|
||||
export let iconProps: any | undefined = undefined
|
||||
export let disabled: boolean = false
|
||||
@ -29,9 +29,16 @@
|
||||
export let inheritColor: boolean = false
|
||||
export let tooltip: LabelAndProps | undefined = undefined
|
||||
export let focusIndex = -1
|
||||
|
||||
let element: ButtonBase | undefined
|
||||
|
||||
export function focus () {
|
||||
element?.focus()
|
||||
}
|
||||
</script>
|
||||
|
||||
<ButtonBase
|
||||
bind:this={element}
|
||||
type={'type-button-icon'}
|
||||
{kind}
|
||||
{size}
|
||||
@ -45,4 +52,5 @@
|
||||
{tooltip}
|
||||
{focusIndex}
|
||||
on:click
|
||||
on:keydown
|
||||
/>
|
||||
|
80
packages/ui/src/components/Chip.svelte
Normal file
80
packages/ui/src/components/Chip.svelte
Normal file
@ -0,0 +1,80 @@
|
||||
<!--
|
||||
// Copyright © 2024 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { IconClose, ButtonIcon } from '..'
|
||||
|
||||
export let label: string
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
let buttonRef: ButtonIcon | undefined
|
||||
|
||||
function handleBackspace (event: KeyboardEvent) {
|
||||
if (event.key === 'Backspace') {
|
||||
dispatch('remove')
|
||||
}
|
||||
}
|
||||
|
||||
export function focus () {
|
||||
buttonRef?.focus()
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="flex items-center font-medium-14 max-w-60 p-1 chip">
|
||||
<span class="px-2 overflow-label">{label}</span>
|
||||
<ButtonIcon
|
||||
bind:this={buttonRef}
|
||||
kind="tertiary"
|
||||
size="min"
|
||||
icon={IconClose}
|
||||
inheritColor={true}
|
||||
on:click={() => dispatch('remove')}
|
||||
on:keydown={handleBackspace}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.chip {
|
||||
position: relative;
|
||||
height: var(--global-small-Size);
|
||||
border: none;
|
||||
color: var(--tag-on-accent-PorpoiseText);
|
||||
background-color: var(--global-accent-BackgroundColor);
|
||||
border-radius: var(--small-BorderRadius);
|
||||
|
||||
&:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
border-radius: var(--small-BorderRadius);
|
||||
overflow: hidden;
|
||||
background-color: transparent;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
&:hover:after {
|
||||
background-color: var(--global-ui-hover-OverlayColor);
|
||||
}
|
||||
|
||||
&:active:after {
|
||||
background-color: var(--global-ui-active-OverlayColor);
|
||||
}
|
||||
|
||||
& :global(button.type-button-icon) {
|
||||
margin-right: var(--spacing-0_25);
|
||||
}
|
||||
}
|
||||
</style>
|
114
packages/ui/src/components/SearchPicker.svelte
Normal file
114
packages/ui/src/components/SearchPicker.svelte
Normal file
@ -0,0 +1,114 @@
|
||||
<!--
|
||||
// Copyright © 2024 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import Chip from './Chip.svelte'
|
||||
|
||||
interface Item {
|
||||
id: string
|
||||
label: string
|
||||
}
|
||||
|
||||
export let autoFocus: boolean = false
|
||||
export let placeholder = ''
|
||||
export let value = ''
|
||||
export let items: Item[] = []
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
let inputRef: HTMLInputElement | undefined
|
||||
const itemsRef: Chip[] = []
|
||||
|
||||
function handleBackspace (event: KeyboardEvent) {
|
||||
if (event.key === 'Backspace' && value === '' && items.length > 0) {
|
||||
itemsRef[items.length - 1].focus()
|
||||
}
|
||||
dispatch('keydown', event)
|
||||
}
|
||||
|
||||
function handleItemRemove (id: string) {
|
||||
dispatch('item-remove', id)
|
||||
inputRef?.focus()
|
||||
}
|
||||
|
||||
export function focus () {
|
||||
inputRef?.focus()
|
||||
autoFocus = false
|
||||
}
|
||||
|
||||
$: if (inputRef !== undefined && autoFocus) {
|
||||
focus()
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div class="flex flex-gap-1 flex-wrap search-picker" on:click={() => inputRef?.focus()}>
|
||||
{#each items as item, i}
|
||||
<Chip
|
||||
bind:this={itemsRef[i]}
|
||||
label={item.label}
|
||||
on:remove={() => {
|
||||
handleItemRemove(item.id)
|
||||
}}
|
||||
/>
|
||||
{/each}
|
||||
<input
|
||||
bind:this={inputRef}
|
||||
class="flex-grow font-regular-14"
|
||||
type="text"
|
||||
autocomplete="off"
|
||||
spellcheck="false"
|
||||
{placeholder}
|
||||
bind:value
|
||||
on:change
|
||||
on:input
|
||||
on:keydown={handleBackspace}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.search-picker {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
padding: var(--spacing-0_5);
|
||||
border-radius: var(--small-focus-BorderRadius);
|
||||
box-shadow: inset 0 0 0 0.0625rem var(--input-BorderColor);
|
||||
cursor: text;
|
||||
|
||||
&:focus-within {
|
||||
box-shadow:
|
||||
inset 0 0 0 0.0625rem var(--input-BorderColor),
|
||||
0 0 0 0.125rem var(--global-focus-inset-BorderColor);
|
||||
outline: 0.125rem solid var(--global-focus-BorderColor);
|
||||
outline-offset: 0.125rem;
|
||||
}
|
||||
|
||||
input {
|
||||
height: var(--global-small-Size);
|
||||
padding: 0;
|
||||
border: none;
|
||||
caret-color: var(--input-search-IconColor);
|
||||
|
||||
&::placeholder {
|
||||
color: var(--global-disabled-TextColor);
|
||||
}
|
||||
|
||||
&:only-child {
|
||||
padding: var(--spacing-0_5) var(--spacing-1_25);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -97,6 +97,8 @@ export { default as Row } from './components/Row.svelte'
|
||||
// export { default as CheckBoxList } from './components/CheckBoxList.svelte.txt'
|
||||
export { default as EditWithIcon } from './components/EditWithIcon.svelte'
|
||||
export { default as SearchEdit } from './components/SearchEdit.svelte'
|
||||
export { default as SearchPicker } from './components/SearchPicker.svelte'
|
||||
export { default as Chip } from './components/Chip.svelte'
|
||||
export { default as Loading } from './components/Loading.svelte'
|
||||
export { default as Spinner } from './components/Spinner.svelte'
|
||||
export { default as Popup } from './components/Popup.svelte'
|
||||
|
@ -39,7 +39,7 @@
|
||||
let listSelection = 0
|
||||
let list: ListView
|
||||
|
||||
let selectedItems = new Set<Ref<Employee>>(selected)
|
||||
$: selectedItems = new Set<Ref<Employee>>(selected)
|
||||
|
||||
let persons: Employee[] = []
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user