poe-svelte-ui-lib 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +3 -3
- package/dist/Accordion/Accordion.svelte +53 -53
- package/dist/Accordion/AccordionProps.svelte +70 -70
- package/dist/Button/Button.svelte +144 -144
- package/dist/Button/ButtonProps.svelte +200 -200
- package/dist/ColorPicker/ColorPicker.svelte +207 -207
- package/dist/ColorPicker/ColorPickerProps.svelte +100 -100
- package/dist/FileAttach/FileAttach.svelte +103 -103
- package/dist/Graph/Graph.svelte +270 -270
- package/dist/Graph/GraphProps.svelte +56 -56
- package/dist/Input/Input.svelte +239 -239
- package/dist/Input/InputProps.svelte +221 -221
- package/dist/Loader.svelte +12 -12
- package/dist/MessageModal.svelte +54 -54
- package/dist/ProgressBar/ProgressBar.svelte +48 -48
- package/dist/ProgressBar/ProgressBarProps.svelte +145 -145
- package/dist/Select/Select.svelte +191 -187
- package/dist/Select/SelectProps.svelte +260 -260
- package/dist/Slider/Slider.svelte +260 -260
- package/dist/Slider/SliderProps.svelte +161 -161
- package/dist/Switch/Switch.svelte +83 -83
- package/dist/Switch/SwitchProps.svelte +144 -144
- package/dist/Table/Table.svelte +276 -276
- package/dist/Table/TableProps.svelte +286 -286
- package/dist/TextField/TextField.svelte +22 -22
- package/dist/TextField/TextFieldProps.svelte +92 -92
- package/dist/{appIcons → libIcons}/ButtonAdd.svelte +10 -10
- package/dist/{appIcons → libIcons}/ButtonDelete.svelte +13 -13
- package/dist/{appIcons → libIcons}/LoaderRotate.svelte +9 -9
- package/dist/locales/CircleFlagsEn.svelte +14 -14
- package/dist/locales/CircleFlagsRu.svelte +8 -8
- package/dist/locales/CircleFlagsZh.svelte +8 -8
- package/package.json +49 -47
- /package/dist/{appIcons → libIcons}/ButtonAdd.svelte.d.ts +0 -0
- /package/dist/{appIcons → libIcons}/ButtonDelete.svelte.d.ts +0 -0
- /package/dist/{appIcons → libIcons}/LoaderRotate.svelte.d.ts +0 -0
|
@@ -1,187 +1,191 @@
|
|
|
1
|
-
<!-- $lib/ElementUI/Select.svelte -->
|
|
2
|
-
<script lang="ts" generics="T = unknown">
|
|
3
|
-
import { slide } from 'svelte/transition'
|
|
4
|
-
import { onMount } from 'svelte'
|
|
5
|
-
import type { ISelectOption, ISelectProps } from '../types'
|
|
6
|
-
import { t } from '../locales/i18n'
|
|
7
|
-
|
|
8
|
-
let isDropdownOpen = $state(false)
|
|
9
|
-
let dropdownElement: HTMLDivElement
|
|
10
|
-
|
|
11
|
-
let searchValue = $state('')
|
|
12
|
-
let filteredOptions = $state<ISelectOption<T>[]>([])
|
|
13
|
-
|
|
14
|
-
let {
|
|
15
|
-
id = { name: '', value: crypto.randomUUID() },
|
|
16
|
-
wrapperClass = 'bg-max',
|
|
17
|
-
disabled = false,
|
|
18
|
-
label = { name: '', class: '' },
|
|
19
|
-
type = 'select',
|
|
20
|
-
value = $bindable(),
|
|
21
|
-
options = [],
|
|
22
|
-
onUpdate,
|
|
23
|
-
}: ISelectProps<T> = $props()
|
|
24
|
-
|
|
25
|
-
/* Закрытие при клике вне компонента */
|
|
26
|
-
const handleClickOutside = (event: MouseEvent) => {
|
|
27
|
-
if (dropdownElement && !dropdownElement.contains(event.target as Node)) {
|
|
28
|
-
isDropdownOpen = false
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
onMount(() => {
|
|
33
|
-
if (type === 'select') document.addEventListener('click', handleClickOutside)
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
{
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
{option
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
{#if option.
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
{
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
{
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
{option
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
1
|
+
<!-- $lib/ElementUI/Select.svelte -->
|
|
2
|
+
<script lang="ts" generics="T = unknown">
|
|
3
|
+
import { slide } from 'svelte/transition'
|
|
4
|
+
import { onMount } from 'svelte'
|
|
5
|
+
import type { ISelectOption, ISelectProps } from '../types'
|
|
6
|
+
import { t } from '../locales/i18n'
|
|
7
|
+
|
|
8
|
+
let isDropdownOpen = $state(false)
|
|
9
|
+
let dropdownElement: HTMLDivElement
|
|
10
|
+
|
|
11
|
+
let searchValue = $state('')
|
|
12
|
+
let filteredOptions = $state<ISelectOption<T>[]>([])
|
|
13
|
+
|
|
14
|
+
let {
|
|
15
|
+
id = { name: '', value: crypto.randomUUID() },
|
|
16
|
+
wrapperClass = 'bg-max',
|
|
17
|
+
disabled = false,
|
|
18
|
+
label = { name: '', class: '' },
|
|
19
|
+
type = 'select',
|
|
20
|
+
value = $bindable(),
|
|
21
|
+
options = [],
|
|
22
|
+
onUpdate,
|
|
23
|
+
}: ISelectProps<T> = $props()
|
|
24
|
+
|
|
25
|
+
/* Закрытие при клике вне компонента */
|
|
26
|
+
const handleClickOutside = (event: MouseEvent) => {
|
|
27
|
+
if (dropdownElement && !dropdownElement.contains(event.target as Node)) {
|
|
28
|
+
isDropdownOpen = false
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
onMount(() => {
|
|
33
|
+
if (type === 'select' || type === 'input') document.addEventListener('click', handleClickOutside)
|
|
34
|
+
if (type === 'input') searchValue = value?.name ?? ''
|
|
35
|
+
return () => {
|
|
36
|
+
if (type === 'select' || type === 'input') document.removeEventListener('click', handleClickOutside)
|
|
37
|
+
}
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
const toggleDropdown = (event: MouseEvent) => {
|
|
41
|
+
event.stopPropagation()
|
|
42
|
+
if (!disabled) {
|
|
43
|
+
isDropdownOpen = !isDropdownOpen
|
|
44
|
+
filteredOptions = []
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const selectOption = (option: ISelectOption<T>, event: MouseEvent) => {
|
|
49
|
+
event.stopPropagation()
|
|
50
|
+
if (!disabled) {
|
|
51
|
+
value = option
|
|
52
|
+
isDropdownOpen = false
|
|
53
|
+
searchValue = option.name?.toString() ?? ''
|
|
54
|
+
filteredOptions = []
|
|
55
|
+
onUpdate?.(value)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const handleSearch = (inputValue: string) => {
|
|
60
|
+
searchValue = inputValue
|
|
61
|
+
|
|
62
|
+
if (inputValue.trim() === '') {
|
|
63
|
+
isDropdownOpen = false
|
|
64
|
+
filteredOptions = []
|
|
65
|
+
} else {
|
|
66
|
+
filteredOptions = options.filter((option) => {
|
|
67
|
+
const optionName = option.name?.toString() || ''
|
|
68
|
+
return optionName.toLowerCase().includes(inputValue.toLowerCase())
|
|
69
|
+
})
|
|
70
|
+
isDropdownOpen = filteredOptions.length > 0
|
|
71
|
+
|
|
72
|
+
const selectedFromList = options.some((option) => option.name?.toString() === searchValue)
|
|
73
|
+
console.log(selectedFromList)
|
|
74
|
+
|
|
75
|
+
if (!selectedFromList) {
|
|
76
|
+
const newOption: ISelectOption<T> = {
|
|
77
|
+
id: `input-${searchValue}`,
|
|
78
|
+
name: searchValue,
|
|
79
|
+
value: searchValue as T,
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
value = newOption
|
|
83
|
+
onUpdate?.(newOption)
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
</script>
|
|
88
|
+
|
|
89
|
+
<div class={`bg-max relative flex w-full flex-col items-center ${wrapperClass}`} bind:this={dropdownElement}>
|
|
90
|
+
{#if label.name}
|
|
91
|
+
<h5 class={`w-full px-4 ${label.class}`}>{label.name}</h5>
|
|
92
|
+
{/if}
|
|
93
|
+
{#if type === 'select'}
|
|
94
|
+
<button
|
|
95
|
+
id={id.value}
|
|
96
|
+
value={value?.value ? String(value.value) : ''}
|
|
97
|
+
class="w-full rounded-2xl border border-[var(--border-color)] p-1 text-center duration-250
|
|
98
|
+
{value?.class} {disabled ? 'opacity-50' : 'cursor-pointer hover:shadow-lg'}"
|
|
99
|
+
style="background: color-mix(in srgb, var(--bg-color), var(--back-color) 70%);"
|
|
100
|
+
onclick={toggleDropdown}
|
|
101
|
+
aria-haspopup="true"
|
|
102
|
+
aria-expanded={isDropdownOpen}
|
|
103
|
+
{disabled}
|
|
104
|
+
>
|
|
105
|
+
{value?.name || $t('common.select_tag')}
|
|
106
|
+
</button>
|
|
107
|
+
|
|
108
|
+
{#if isDropdownOpen}
|
|
109
|
+
<div
|
|
110
|
+
class="absolute top-full left-1/2 z-50 -translate-x-1/2 rounded-b-2xl border border-t-0 border-[var(--border-color)]"
|
|
111
|
+
style="width: calc(100% - 1.8rem);"
|
|
112
|
+
transition:slide={{ duration: 250 }}
|
|
113
|
+
>
|
|
114
|
+
{#each options as option, index (option.id)}
|
|
115
|
+
<button
|
|
116
|
+
id={option.id}
|
|
117
|
+
value={option?.value ? String(option.value) : ''}
|
|
118
|
+
class="flex h-full w-full cursor-pointer items-center justify-center p-1 duration-250 hover:!bg-[var(--field-color)]
|
|
119
|
+
{option.class} {index === options.length - 1 ? 'rounded-b-2xl' : ''} "
|
|
120
|
+
onclick={(e) => selectOption(option, e)}
|
|
121
|
+
{disabled}
|
|
122
|
+
style="background: color-mix(in srgb, var(--bg-color), var(--back-color) 70%);"
|
|
123
|
+
>
|
|
124
|
+
{option.name}
|
|
125
|
+
</button>
|
|
126
|
+
{/each}
|
|
127
|
+
</div>
|
|
128
|
+
{/if}
|
|
129
|
+
{:else if type === 'buttons'}
|
|
130
|
+
<div id={id.value} class="flex h-full w-full flex-row justify-center">
|
|
131
|
+
{#each options as option, index (option.id)}
|
|
132
|
+
<button
|
|
133
|
+
id={option.id}
|
|
134
|
+
class="m-0 inline-block min-w-0 flex-1 items-center border
|
|
135
|
+
border-[var(--border-color)] bg-[var(--bg-color)] px-2 py-1 font-semibold transition-all duration-200 select-none
|
|
136
|
+
{option.disabled || disabled ? 'opacity-50' : 'cursor-pointer hover:shadow-lg'}
|
|
137
|
+
{option.value === value?.value && value !== null ? 'z-10 text-blue-600 ring-2 ring-[var(--blue-color)]' : ''}
|
|
138
|
+
{option.class} {options.length > 0 && index === 0 ? 'rounded-l-2xl' : ''} {index === options.length - 1 ? 'rounded-r-2xl' : ''}"
|
|
139
|
+
onclick={(e) => selectOption(option, e)}
|
|
140
|
+
disabled={option.disabled}
|
|
141
|
+
>
|
|
142
|
+
<span class="flex flex-row items-center justify-center gap-4">
|
|
143
|
+
{#if option.icon?.component}
|
|
144
|
+
{@const IconComponent = option.icon?.component}
|
|
145
|
+
<IconComponent {...option.icon?.properties} />
|
|
146
|
+
{/if}
|
|
147
|
+
{#if option.name}
|
|
148
|
+
<div class="flex-1">
|
|
149
|
+
{option.name}
|
|
150
|
+
</div>
|
|
151
|
+
{/if}
|
|
152
|
+
</span>
|
|
153
|
+
</button>
|
|
154
|
+
{/each}
|
|
155
|
+
</div>
|
|
156
|
+
{:else if type === 'input'}
|
|
157
|
+
<input
|
|
158
|
+
bind:value={searchValue}
|
|
159
|
+
class="w-full appearance-none rounded-2xl border px-4 py-1 text-center transition-shadow
|
|
160
|
+
outline-none hover:shadow-md focus:border-blue-400
|
|
161
|
+
[&::-webkit-inner-spin-button]:hidden [&::-webkit-outer-spin-button]:hidden
|
|
162
|
+
{disabled ? 'cursor-not-allowed opacity-50' : 'cursor-text'} border-[var(--border-color)]"
|
|
163
|
+
style="background: color-mix(in srgb, var(--bg-color), var(--back-color) 70%);"
|
|
164
|
+
id={id.value}
|
|
165
|
+
{disabled}
|
|
166
|
+
oninput={(e) => handleSearch((e.currentTarget as HTMLInputElement).value)}
|
|
167
|
+
/>
|
|
168
|
+
|
|
169
|
+
{#if isDropdownOpen}
|
|
170
|
+
<div
|
|
171
|
+
class="absolute top-full left-1/2 z-50 -translate-x-1/2 rounded-b-2xl border border-t-0 border-[var(--border-color)]"
|
|
172
|
+
style="width: calc(100% - 1.8rem);"
|
|
173
|
+
transition:slide={{ duration: 250 }}
|
|
174
|
+
>
|
|
175
|
+
{#each filteredOptions as option, index (option.id)}
|
|
176
|
+
<button
|
|
177
|
+
id={option.id}
|
|
178
|
+
value={option?.value ? String(option.value) : ''}
|
|
179
|
+
class="flex h-full w-full cursor-pointer items-center justify-center p-1 duration-250 hover:!bg-[var(--field-color)]
|
|
180
|
+
{option.class} {index === filteredOptions.length - 1 ? 'rounded-b-2xl' : ''} "
|
|
181
|
+
onclick={(e) => selectOption(option, e)}
|
|
182
|
+
{disabled}
|
|
183
|
+
style="background: color-mix(in srgb, var(--bg-color), var(--back-color) 70%);"
|
|
184
|
+
>
|
|
185
|
+
{option.name}
|
|
186
|
+
</button>
|
|
187
|
+
{/each}
|
|
188
|
+
</div>
|
|
189
|
+
{/if}
|
|
190
|
+
{/if}
|
|
191
|
+
</div>
|