poe-svelte-ui-lib 1.6.8 → 1.6.10
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/dist/Select/Select.svelte +41 -51
- package/dist/Select/Select.svelte.d.ts +1 -1
- package/dist/Slider/Slider.svelte +45 -60
- package/dist/Slider/Slider.svelte.d.ts +1 -1
- package/dist/Table/Table.svelte +23 -43
- package/dist/Tabs/Tabs.svelte +17 -22
- package/dist/Tabs/Tabs.svelte.d.ts +1 -1
- package/package.json +1 -1
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
<!-- $lib/ElementUI/Select.svelte -->
|
|
2
2
|
<script lang="ts" generics="T = unknown">
|
|
3
|
-
import { slide } from
|
|
4
|
-
import { onMount } from
|
|
5
|
-
import type { ISelectOption, ISelectProps } from
|
|
6
|
-
import { twMerge } from
|
|
7
|
-
import { t } from
|
|
3
|
+
import { slide } from "svelte/transition"
|
|
4
|
+
import { onMount } from "svelte"
|
|
5
|
+
import type { ISelectOption, ISelectProps } from "../types"
|
|
6
|
+
import { twMerge } from "tailwind-merge"
|
|
7
|
+
import { t } from "../locales/i18n"
|
|
8
8
|
|
|
9
9
|
let isDropdownOpen = $state(false)
|
|
10
10
|
let dropdownElement: HTMLDivElement
|
|
11
11
|
|
|
12
12
|
let {
|
|
13
13
|
id = crypto.randomUUID(),
|
|
14
|
-
wrapperClass =
|
|
14
|
+
wrapperClass = "",
|
|
15
15
|
disabled = false,
|
|
16
|
-
label = { name:
|
|
17
|
-
type =
|
|
16
|
+
label = { name: "", class: "" },
|
|
17
|
+
type = "select",
|
|
18
18
|
value = $bindable(),
|
|
19
19
|
options = [],
|
|
20
20
|
onUpdate,
|
|
21
21
|
}: ISelectProps<T> = $props()
|
|
22
22
|
|
|
23
|
-
let searchValue: any = $state(
|
|
23
|
+
let searchValue: any = $state("")
|
|
24
24
|
let filteredOptions = $state<ISelectOption<T>[]>([])
|
|
25
25
|
|
|
26
26
|
/* Закрытие при клике вне компонента */
|
|
@@ -44,10 +44,10 @@
|
|
|
44
44
|
})
|
|
45
45
|
|
|
46
46
|
onMount(() => {
|
|
47
|
-
if (type ===
|
|
48
|
-
if (type ===
|
|
47
|
+
if (type === "select" || type === "input") document.addEventListener("click", handleClickOutside)
|
|
48
|
+
if (type === "input") searchValue = value?.name ?? ""
|
|
49
49
|
return () => {
|
|
50
|
-
if (type ===
|
|
50
|
+
if (type === "select" || type === "input") document.removeEventListener("click", handleClickOutside)
|
|
51
51
|
}
|
|
52
52
|
})
|
|
53
53
|
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
if (!disabled) {
|
|
65
65
|
value = option
|
|
66
66
|
isDropdownOpen = false
|
|
67
|
-
searchValue = option.name?.toString() ??
|
|
67
|
+
searchValue = option.name?.toString() ?? ""
|
|
68
68
|
filteredOptions = []
|
|
69
69
|
onUpdate?.(value)
|
|
70
70
|
}
|
|
@@ -73,17 +73,17 @@
|
|
|
73
73
|
const handleSearch = (inputValue: string) => {
|
|
74
74
|
searchValue = inputValue
|
|
75
75
|
|
|
76
|
-
if (inputValue.trim() ===
|
|
76
|
+
if (inputValue.trim() === "") {
|
|
77
77
|
isDropdownOpen = false
|
|
78
78
|
filteredOptions = []
|
|
79
79
|
} else {
|
|
80
|
-
filteredOptions = options.filter(
|
|
81
|
-
const optionName = option.name?.toString() ||
|
|
80
|
+
filteredOptions = options.filter(option => {
|
|
81
|
+
const optionName = option.name?.toString() || ""
|
|
82
82
|
return optionName.toLowerCase().includes(inputValue.toLowerCase())
|
|
83
83
|
})
|
|
84
84
|
isDropdownOpen = filteredOptions.length > 0
|
|
85
85
|
|
|
86
|
-
const selectedFromList = options.find(
|
|
86
|
+
const selectedFromList = options.find(option => option.name?.toString() === searchValue)
|
|
87
87
|
|
|
88
88
|
if (!selectedFromList) {
|
|
89
89
|
const newOption: ISelectOption<T> = {
|
|
@@ -91,7 +91,6 @@
|
|
|
91
91
|
name: searchValue,
|
|
92
92
|
value: searchValue as T,
|
|
93
93
|
}
|
|
94
|
-
|
|
95
94
|
value = newOption
|
|
96
95
|
onUpdate?.(newOption)
|
|
97
96
|
} else {
|
|
@@ -106,50 +105,47 @@
|
|
|
106
105
|
{#if label.name}
|
|
107
106
|
<h5 class={twMerge(`w-full px-4`, label.class)}>{label.name}</h5>
|
|
108
107
|
{/if}
|
|
109
|
-
{#if type ===
|
|
108
|
+
{#if type === "select"}
|
|
110
109
|
<button
|
|
111
110
|
id={`${id}-${crypto.randomUUID().slice(0, 6)}`}
|
|
112
|
-
value={value?.value ? String(value.value) :
|
|
111
|
+
value={value?.value ? String(value.value) : ""}
|
|
113
112
|
class={twMerge(
|
|
114
113
|
`w-full rounded-2xl border border-(--bg-color) p-1 text-center shadow-[0_0_3px_rgb(0_0_0_/0.25)] transition duration-200
|
|
115
|
-
${disabled ?
|
|
114
|
+
${disabled ? "opacity-50" : "cursor-pointer hover:shadow-[0_0_6px_rgb(0_0_0_/0.25)]"}`,
|
|
116
115
|
value?.class,
|
|
117
116
|
)}
|
|
118
117
|
style="background: color-mix(in srgb, var(--bg-color), var(--back-color) 70%); "
|
|
119
118
|
onclick={toggleDropdown}
|
|
120
119
|
aria-haspopup="true"
|
|
121
120
|
aria-expanded={isDropdownOpen}
|
|
122
|
-
{disabled}
|
|
123
|
-
|
|
124
|
-
{value?.name || $t('common.select_tag')}
|
|
121
|
+
{disabled}>
|
|
122
|
+
{value?.name || $t("common.select_tag")}
|
|
125
123
|
</button>
|
|
126
124
|
|
|
127
125
|
{#if isDropdownOpen}
|
|
128
126
|
<div
|
|
129
127
|
class="absolute top-full left-1/2 z-50 -translate-x-1/2 rounded-b-2xl shadow-[0_0_3px_rgb(0_0_0_/0.25)]"
|
|
130
128
|
style="width: calc(100% - 1.8rem);"
|
|
131
|
-
transition:slide={{ duration: 250 }}
|
|
132
|
-
>
|
|
129
|
+
transition:slide={{ duration: 250 }}>
|
|
133
130
|
{#each options as option, index (option.id)}
|
|
134
131
|
<button
|
|
135
132
|
id={option.id}
|
|
136
|
-
value={option?.value ? String(option.value) :
|
|
133
|
+
value={option?.value ? String(option.value) : ""}
|
|
137
134
|
class={twMerge(
|
|
138
135
|
`flex h-full w-full cursor-pointer items-center justify-center p-1 inset-shadow-[0_10px_10px_-15px_rgb(0_0_0_/0.5)] duration-250 hover:bg-(--field-color)!
|
|
139
|
-
${index === options.length - 1 ?
|
|
136
|
+
${index === options.length - 1 ? "rounded-b-2xl" : ""} `,
|
|
140
137
|
option.class,
|
|
141
138
|
)}
|
|
142
|
-
onclick={
|
|
139
|
+
onclick={e => selectOption(option, e)}
|
|
143
140
|
{disabled}
|
|
144
141
|
style="background: color-mix(in srgb, var(--bg-color), var(--back-color) 70%);
|
|
145
|
-
"
|
|
146
|
-
>
|
|
142
|
+
">
|
|
147
143
|
{option.name}
|
|
148
144
|
</button>
|
|
149
145
|
{/each}
|
|
150
146
|
</div>
|
|
151
147
|
{/if}
|
|
152
|
-
{:else if type ===
|
|
148
|
+
{:else if type === "buttons"}
|
|
153
149
|
<div id={`${id}-${crypto.randomUUID().slice(0, 6)}`} class="flex h-full w-full flex-row justify-center rounded-full">
|
|
154
150
|
{#each options as option, index (option.id)}
|
|
155
151
|
<button
|
|
@@ -161,9 +157,8 @@
|
|
|
161
157
|
${options.length > 0 && index === 0 ? 'rounded-l-2xl' : ''} ${index === options.length - 1 ? 'rounded-r-2xl' : ''}`,
|
|
162
158
|
option.class,
|
|
163
159
|
)} bg-(--bg-color)"
|
|
164
|
-
onclick={
|
|
165
|
-
disabled={option.disabled}
|
|
166
|
-
>
|
|
160
|
+
onclick={e => selectOption(option, e)}
|
|
161
|
+
disabled={option.disabled}>
|
|
167
162
|
<span class="flex flex-row items-center justify-center gap-4">
|
|
168
163
|
{#if option.name}
|
|
169
164
|
<div class="flex-1">
|
|
@@ -174,47 +169,42 @@
|
|
|
174
169
|
</button>
|
|
175
170
|
{/each}
|
|
176
171
|
</div>
|
|
177
|
-
{:else if type ===
|
|
172
|
+
{:else if type === "input"}
|
|
178
173
|
<input
|
|
179
174
|
bind:value={searchValue}
|
|
180
175
|
class="w-full appearance-none rounded-2xl border px-4 py-1 text-center shadow-[0_0_3px_rgb(0_0_0_/0.25)]
|
|
181
176
|
transition duration-200 outline-none focus:shadow-[0_0_6px_var(--blue-color)]
|
|
182
177
|
[&::-webkit-inner-spin-button]:hidden [&::-webkit-outer-spin-button]:hidden
|
|
183
|
-
{disabled
|
|
184
|
-
? 'cursor-not-allowed opacity-50'
|
|
185
|
-
: 'cursor-text'} border-(--bg-color) focus:border-(--blue-color) hover:shadow-[0_0_6px_rgb(0_0_0_/0.25)]"
|
|
178
|
+
{disabled ? 'cursor-not-allowed opacity-50' : 'cursor-text'} border-(--bg-color) focus:border-(--blue-color) hover:shadow-[0_0_6px_rgb(0_0_0_/0.25)]"
|
|
186
179
|
style="background: color-mix(in srgb, var(--bg-color), var(--back-color) 70%);"
|
|
187
180
|
id={`${id}-${crypto.randomUUID().slice(0, 6)}`}
|
|
188
181
|
{disabled}
|
|
189
|
-
oninput={
|
|
190
|
-
onclick={
|
|
191
|
-
if (searchValue ==
|
|
182
|
+
oninput={e => handleSearch((e.currentTarget as HTMLInputElement).value)}
|
|
183
|
+
onclick={e => {
|
|
184
|
+
if (searchValue == "") {
|
|
192
185
|
filteredOptions = options
|
|
193
186
|
isDropdownOpen = true
|
|
194
187
|
}
|
|
195
|
-
}}
|
|
196
|
-
/>
|
|
188
|
+
}} />
|
|
197
189
|
|
|
198
190
|
{#if isDropdownOpen}
|
|
199
191
|
<div
|
|
200
192
|
class="absolute top-full left-1/2 z-50 -translate-x-1/2 rounded-b-2xl border border-t-0 border-(--bg-color) shadow-[0_0_3px_rgb(0_0_0_/0.25)]"
|
|
201
193
|
style="width: calc(100% - 1.8rem);"
|
|
202
|
-
transition:slide={{ duration: 250 }}
|
|
203
|
-
>
|
|
194
|
+
transition:slide={{ duration: 250 }}>
|
|
204
195
|
{#each filteredOptions as option, index (option.id)}
|
|
205
196
|
<button
|
|
206
197
|
id={option.id}
|
|
207
|
-
value={option?.value ? String(option.value) :
|
|
198
|
+
value={option?.value ? String(option.value) : ""}
|
|
208
199
|
class={twMerge(
|
|
209
200
|
`flex h-full w-full cursor-pointer items-center justify-center p-1 inset-shadow-[0_10px_10px_-15px_rgb(0_0_0_/0.5)] duration-250 hover:bg-(--field-color)!
|
|
210
|
-
${index === filteredOptions.length - 1 ?
|
|
201
|
+
${index === filteredOptions.length - 1 ? "rounded-b-2xl" : ""} `,
|
|
211
202
|
option.class,
|
|
212
203
|
)}
|
|
213
|
-
onclick={
|
|
204
|
+
onclick={e => selectOption(option, e)}
|
|
214
205
|
{disabled}
|
|
215
206
|
style="background: color-mix(in srgb, var(--bg-color), var(--back-color) 70%);
|
|
216
|
-
"
|
|
217
|
-
>
|
|
207
|
+
">
|
|
218
208
|
{option.name}
|
|
219
209
|
</button>
|
|
220
210
|
{/each}
|
|
@@ -1,45 +1,44 @@
|
|
|
1
1
|
<!-- $lib/ElementsUI/Slider.svelte -->
|
|
2
2
|
<script lang="ts">
|
|
3
|
-
import type { ISliderProps } from
|
|
4
|
-
import { twMerge } from
|
|
5
|
-
import { onDestroy, onMount } from 'svelte'
|
|
3
|
+
import type { ISliderProps } from "../types"
|
|
4
|
+
import { twMerge } from "tailwind-merge"
|
|
6
5
|
|
|
7
6
|
let {
|
|
8
7
|
id = crypto.randomUUID(),
|
|
9
|
-
wrapperClass =
|
|
10
|
-
label = { name:
|
|
11
|
-
type =
|
|
8
|
+
wrapperClass = "",
|
|
9
|
+
label = { name: "", class: "" },
|
|
10
|
+
type = "single",
|
|
12
11
|
value = 0,
|
|
13
12
|
number = { minNum: 0, maxNum: 10, step: 1 },
|
|
14
13
|
disabled = false,
|
|
15
14
|
onUpdate = () => {},
|
|
16
15
|
}: ISliderProps = $props()
|
|
17
16
|
|
|
18
|
-
const isRange = $derived(type ===
|
|
17
|
+
const isRange = $derived(type === "range" || (Array.isArray(value) && value.length === 2))
|
|
19
18
|
|
|
20
19
|
const maxDigits = $derived(String(number.maxNum ?? 100).length)
|
|
21
20
|
const valueWidth = $derived(`${maxDigits + 1}ch`) /* +1 на запас */
|
|
22
21
|
|
|
23
22
|
/* Инициализация значений с проверкой типа */
|
|
24
|
-
let singleValue = $derived(!isRange && typeof value ===
|
|
23
|
+
let singleValue = $derived(!isRange && typeof value === "number" ? value : number.minNum)
|
|
25
24
|
let lowerValue = $derived(isRange && Array.isArray(value) ? value[0] : number.minNum)
|
|
26
25
|
let upperValue = $derived(isRange && Array.isArray(value) ? value[1] : number.maxNum)
|
|
27
26
|
|
|
28
|
-
let activeRound:
|
|
27
|
+
let activeRound: "floor" | "ceil" = $state("floor")
|
|
29
28
|
|
|
30
29
|
let centerNum = $derived(lowerValue + Math[activeRound](Math.abs(upperValue - lowerValue) / 2 / number.step) * number.step)
|
|
31
30
|
|
|
32
31
|
$effect(() => {
|
|
33
32
|
if (value === undefined || value === null) {
|
|
34
|
-
if (type ===
|
|
35
|
-
if (type ===
|
|
33
|
+
if (type === "single" && !value) value = number.minNum
|
|
34
|
+
if (type === "range" && !value) value = [number.minNum, number.maxNum]
|
|
36
35
|
}
|
|
37
36
|
})
|
|
38
37
|
|
|
39
|
-
const adjustValue = (target:
|
|
40
|
-
const stepValue = direction ===
|
|
41
|
-
if (isRange && target !==
|
|
42
|
-
if (target ===
|
|
38
|
+
const adjustValue = (target: "lower" | "upper" | "single", direction: "increment" | "decrement") => {
|
|
39
|
+
const stepValue = direction === "increment" ? number.step : -number.step
|
|
40
|
+
if (isRange && target !== "single") {
|
|
41
|
+
if (target === "lower") {
|
|
43
42
|
lowerValue = roundToClean(Math.max(number.minNum, Math.min(lowerValue + stepValue, upperValue)))
|
|
44
43
|
lowerValue = roundToClean(lowerValue == upperValue ? upperValue - number.step : lowerValue)
|
|
45
44
|
} else {
|
|
@@ -57,7 +56,7 @@
|
|
|
57
56
|
if (Array.isArray(value)) {
|
|
58
57
|
lowerValue = value[0]
|
|
59
58
|
upperValue = value[1]
|
|
60
|
-
} else if (typeof value ===
|
|
59
|
+
} else if (typeof value === "number") {
|
|
61
60
|
singleValue = value
|
|
62
61
|
}
|
|
63
62
|
})
|
|
@@ -83,8 +82,7 @@
|
|
|
83
82
|
<!-- Слайдер -->
|
|
84
83
|
<div
|
|
85
84
|
id={`${id}-${crypto.randomUUID().slice(0, 6)}`}
|
|
86
|
-
class="relative flex h-8 w-full items-center justify-center rounded-full {disabled ? 'cursor-not-allowed opacity-50' : ''}"
|
|
87
|
-
>
|
|
85
|
+
class="relative flex h-8 w-full items-center justify-center rounded-full {disabled ? 'cursor-not-allowed opacity-50' : ''}">
|
|
88
86
|
{#if isRange}
|
|
89
87
|
{@const userAgent = navigator.userAgent}
|
|
90
88
|
|
|
@@ -97,12 +95,12 @@
|
|
|
97
95
|
bind:value={lowerValue}
|
|
98
96
|
oninput={disabled
|
|
99
97
|
? undefined
|
|
100
|
-
:
|
|
98
|
+
: e => {
|
|
101
99
|
const newValue = Math.min(Number((e.target as HTMLInputElement).value), upperValue)
|
|
102
100
|
lowerValue = roundToClean(newValue == upperValue ? upperValue - number.step : newValue)
|
|
103
101
|
onUpdate([lowerValue, upperValue])
|
|
104
102
|
}}
|
|
105
|
-
onmousedown={() => (activeRound =
|
|
103
|
+
onmousedown={() => (activeRound = "ceil")}
|
|
106
104
|
{disabled}
|
|
107
105
|
class={twMerge(
|
|
108
106
|
`basis-[calc(${(Math.abs(centerNum - number.minNum) / Math.abs(number.maxNum - number.minNum)) * 100}%+2rem+5px)] h-8 w-full appearance-none overflow-hidden
|
|
@@ -117,9 +115,9 @@
|
|
|
117
115
|
[&::-webkit-slider-thumb]:rounded-full
|
|
118
116
|
[&::-webkit-slider-thumb]:shadow-[var(--focus-shadow),]
|
|
119
117
|
${
|
|
120
|
-
userAgent.includes(
|
|
121
|
-
?
|
|
122
|
-
:
|
|
118
|
+
userAgent.includes("iOS") || userAgent.includes("iPhone") || userAgent.includes("iPad")
|
|
119
|
+
? "[&::-webkit-slider-thumb]:ring-[6.5px]"
|
|
120
|
+
: "[&::-webkit-slider-thumb]:ring-[5px] "
|
|
123
121
|
}
|
|
124
122
|
[&::-moz-range-thumb]:relative
|
|
125
123
|
[&::-moz-range-thumb]:ml-[-0.4rem]
|
|
@@ -134,8 +132,7 @@
|
|
|
134
132
|
`[&::-moz-range-thumb]:shadow-[calc(100rem+0.5rem)_0_0_100rem]
|
|
135
133
|
[&::-webkit-slider-thumb]:shadow-[calc(100rem+0.5rem)_0_0_100rem]`,
|
|
136
134
|
)}
|
|
137
|
-
style="color: var(--bg-color); flex-basis: {`calc(${(Math.abs(centerNum - number.minNum) / Math.abs(number.maxNum - number.minNum)) * 100}% + 2rem + 5px)`};"
|
|
138
|
-
/>
|
|
135
|
+
style="color: var(--bg-color); flex-basis: {`calc(${(Math.abs(centerNum - number.minNum) / Math.abs(number.maxNum - number.minNum)) * 100}% + 2rem + 5px)`};" />
|
|
139
136
|
<input
|
|
140
137
|
type="range"
|
|
141
138
|
min={centerNum}
|
|
@@ -144,12 +141,12 @@
|
|
|
144
141
|
bind:value={upperValue}
|
|
145
142
|
oninput={disabled
|
|
146
143
|
? undefined
|
|
147
|
-
:
|
|
144
|
+
: e => {
|
|
148
145
|
const newValue = Math.max(Number((e.target as HTMLInputElement).value), lowerValue)
|
|
149
146
|
upperValue = roundToClean(newValue == lowerValue ? newValue + number.step : upperValue)
|
|
150
147
|
onUpdate([lowerValue, upperValue])
|
|
151
148
|
}}
|
|
152
|
-
onmousedown={() => (activeRound =
|
|
149
|
+
onmousedown={() => (activeRound = "floor")}
|
|
153
150
|
{disabled}
|
|
154
151
|
class={twMerge(
|
|
155
152
|
`basis-[calc(${100 - (Math.abs(centerNum - number.minNum) / Math.abs(number.maxNum - number.minNum)) * 100}%+2rem+5px)] h-8 w-full appearance-none overflow-hidden
|
|
@@ -164,9 +161,9 @@
|
|
|
164
161
|
[&::-webkit-slider-thumb]:rounded-full
|
|
165
162
|
[&::-webkit-slider-thumb]:shadow-[var(--focus-shadow),]
|
|
166
163
|
${
|
|
167
|
-
userAgent.includes(
|
|
168
|
-
?
|
|
169
|
-
:
|
|
164
|
+
userAgent.includes("iOS") || userAgent.includes("iPhone") || userAgent.includes("iPad")
|
|
165
|
+
? "[&::-webkit-slider-thumb]:ring-[6.5px]"
|
|
166
|
+
: "[&::-webkit-slider-thumb]:ring-[5px] "
|
|
170
167
|
}
|
|
171
168
|
[&::-moz-range-thumb]:relative
|
|
172
169
|
[&::-moz-range-thumb]:ml-[-0.4rem]
|
|
@@ -181,8 +178,7 @@
|
|
|
181
178
|
`[&::-moz-range-thumb]:shadow-[calc(100rem*-1-0.5rem)_0_0_100rem]
|
|
182
179
|
[&::-webkit-slider-thumb]:shadow-[calc(100rem*-1-0.5rem)_0_0_100rem]`,
|
|
183
180
|
)}
|
|
184
|
-
style="color: var(--bg-color); flex-basis: {`calc(${(1 - Math.abs(centerNum - number.minNum) / Math.abs(number.maxNum - number.minNum)) * 100}% + 2rem + 5px)`};"
|
|
185
|
-
/>
|
|
181
|
+
style="color: var(--bg-color); flex-basis: {`calc(${(1 - Math.abs(centerNum - number.minNum) / Math.abs(number.maxNum - number.minNum)) * 100}% + 2rem + 5px)`};" />
|
|
186
182
|
</div>
|
|
187
183
|
{:else}
|
|
188
184
|
{@const userAgent = navigator.userAgent}
|
|
@@ -209,9 +205,9 @@
|
|
|
209
205
|
[&::-webkit-slider-thumb]:rounded-full
|
|
210
206
|
[&::-webkit-slider-thumb]:shadow-[var(--focus-shadow),]
|
|
211
207
|
${
|
|
212
|
-
userAgent.includes(
|
|
213
|
-
?
|
|
214
|
-
:
|
|
208
|
+
userAgent.includes("iOS") || userAgent.includes("iPhone") || userAgent.includes("iPad")
|
|
209
|
+
? "pl-3.5 [&::-webkit-slider-thumb]:ring-[6.5px]"
|
|
210
|
+
: "pl-3 [&::-webkit-slider-thumb]:ring-[5px]"
|
|
215
211
|
}
|
|
216
212
|
[&::-moz-range-thumb]:relative
|
|
217
213
|
[&::-moz-range-thumb]:ml-[-0.4rem]
|
|
@@ -226,53 +222,42 @@
|
|
|
226
222
|
`[&::-moz-range-thumb]:shadow-[calc(100rem*-1-0.5rem)_0_0_100rem]
|
|
227
223
|
[&::-webkit-slider-thumb]:shadow-[calc(100rem*-1-0.5rem)_0_0_100rem]`,
|
|
228
224
|
)}
|
|
229
|
-
style="color: var(--bg-color);"
|
|
230
|
-
/>
|
|
225
|
+
style="color: var(--bg-color);" />
|
|
231
226
|
</div>
|
|
232
227
|
{/if}
|
|
233
228
|
</div>
|
|
234
229
|
|
|
235
230
|
<!-- Кнопки управления -->
|
|
236
|
-
<div class={`mt-3 flex w-full ${isRange ?
|
|
231
|
+
<div class={`mt-3 flex w-full ${isRange ? "justify-between" : "justify-center"} gap-2`}>
|
|
237
232
|
{#if isRange}
|
|
238
|
-
{#each [
|
|
239
|
-
<div
|
|
240
|
-
class={`flex items-center justify-center gap-2 rounded-full px-2 ${disabled ? 'opacity-70' : ''}`}
|
|
241
|
-
style="background-color: var(--bg-color)"
|
|
242
|
-
>
|
|
233
|
+
{#each ["lower", "upper"] as type (type)}
|
|
234
|
+
<div class={`flex items-center justify-center gap-2 rounded-full px-2 ${disabled ? "opacity-70" : ""}`} style="background-color: var(--bg-color)">
|
|
243
235
|
<button
|
|
244
236
|
class="h-full w-4 {disabled ? '' : 'cursor-pointer'}"
|
|
245
|
-
onclick={disabled ? undefined : () => adjustValue(type as
|
|
246
|
-
disabled={disabled || (type ===
|
|
247
|
-
>
|
|
237
|
+
onclick={disabled ? undefined : () => adjustValue(type as "lower" | "upper", "decrement")}
|
|
238
|
+
disabled={disabled || (type === "lower" ? lowerValue <= number.minNum : upperValue <= lowerValue)}>−</button>
|
|
248
239
|
<span class="inline-block text-center tabular-nums" style={`width: ${valueWidth}`}>
|
|
249
|
-
{type ===
|
|
240
|
+
{type === "lower" ? lowerValue : upperValue}
|
|
250
241
|
</span>
|
|
251
242
|
<button
|
|
252
243
|
class="h-full w-4 {disabled ? '' : 'cursor-pointer'}"
|
|
253
|
-
onclick={disabled ? undefined : () => adjustValue(type as
|
|
254
|
-
disabled={disabled || (type ===
|
|
255
|
-
>
|
|
244
|
+
onclick={disabled ? undefined : () => adjustValue(type as "lower" | "upper", "increment")}
|
|
245
|
+
disabled={disabled || (type === "lower" ? lowerValue >= upperValue : upperValue >= number.maxNum)}>+</button>
|
|
256
246
|
</div>
|
|
257
247
|
{/each}
|
|
258
248
|
{:else}
|
|
259
|
-
<div
|
|
260
|
-
class={`flex items-center justify-center gap-2 rounded-full px-2 ${disabled ? 'opacity-70' : ''}`}
|
|
261
|
-
style="background-color: var(--bg-color)"
|
|
262
|
-
>
|
|
249
|
+
<div class={`flex items-center justify-center gap-2 rounded-full px-2 ${disabled ? "opacity-70" : ""}`} style="background-color: var(--bg-color)">
|
|
263
250
|
<button
|
|
264
251
|
class="h-full w-4 {disabled ? '' : 'cursor-pointer'}"
|
|
265
|
-
onclick={disabled ? undefined : () => adjustValue(
|
|
266
|
-
disabled={disabled || singleValue <= number.minNum}>−</button
|
|
267
|
-
>
|
|
252
|
+
onclick={disabled ? undefined : () => adjustValue("single", "decrement")}
|
|
253
|
+
disabled={disabled || singleValue <= number.minNum}>−</button>
|
|
268
254
|
<span class="inline-block text-center tabular-nums" style={`width: ${valueWidth}`}>
|
|
269
255
|
{singleValue}
|
|
270
256
|
</span>
|
|
271
257
|
<button
|
|
272
258
|
class="h-full w-4 {disabled ? '' : 'cursor-pointer'}"
|
|
273
|
-
onclick={disabled ? undefined : () => adjustValue(
|
|
274
|
-
disabled={disabled || singleValue >= number.maxNum}>+</button
|
|
275
|
-
>
|
|
259
|
+
onclick={disabled ? undefined : () => adjustValue("single", "increment")}
|
|
260
|
+
disabled={disabled || singleValue >= number.maxNum}>+</button>
|
|
276
261
|
</div>
|
|
277
262
|
{/if}
|
|
278
263
|
</div>
|
package/dist/Table/Table.svelte
CHANGED
|
@@ -107,8 +107,7 @@
|
|
|
107
107
|
}
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
-
let isDropdownOpen: number | null = $state(null)
|
|
111
|
-
|
|
110
|
+
let isDropdownOpen: { x: number; y: number } | null = $state(null)
|
|
112
111
|
const selectOption = (index: number, key: any, option: ISelectOption<string | number>, event: MouseEvent) => {
|
|
113
112
|
event.stopPropagation()
|
|
114
113
|
|
|
@@ -121,7 +120,7 @@
|
|
|
121
120
|
)
|
|
122
121
|
}
|
|
123
122
|
|
|
124
|
-
let copiedCell
|
|
123
|
+
let copiedCell: { x: number; y: number } | null = $state(null)
|
|
125
124
|
let tooltip = $state({ show: false, text: "", x: 0, y: 0 })
|
|
126
125
|
|
|
127
126
|
const showModal = async (text: string, formatting?: (text: string) => string) => {
|
|
@@ -269,21 +268,15 @@
|
|
|
269
268
|
{/if}
|
|
270
269
|
|
|
271
270
|
<div
|
|
272
|
-
class="relative flex h-full w-full flex-col overflow-hidden rounded-xl border shadow-sm transition duration-200 hover:shadow-md
|
|
273
|
-
|
|
274
|
-
: 'border-transparent'} ">
|
|
271
|
+
class="relative flex h-full w-full flex-col overflow-hidden rounded-xl border shadow-sm transition duration-200 hover:shadow-md
|
|
272
|
+
{outline ? ' border-(--border-color)' : 'border-transparent'} ">
|
|
275
273
|
<!-- Table Header -->
|
|
276
274
|
<div class="grid font-semibold" style={`grid-template-columns: ${header.map(c => c.width || "minmax(0, 1fr)").join(" ")};`}>
|
|
277
275
|
{#each header as column, index (column)}
|
|
278
276
|
<div
|
|
279
277
|
class={twMerge(
|
|
280
|
-
`items-center justify-center border-l ${outline && index !== 0 ? " border-(--border-color)" : "border-transparent"}
|
|
281
|
-
|
|
282
|
-
? "flex justify-center text-center"
|
|
283
|
-
: column.align === "right"
|
|
284
|
-
? "flex justify-end text-right"
|
|
285
|
-
: "flex justify-start text-left"
|
|
286
|
-
} gap-1 bg-(--bg-color) p-2 text-left`,
|
|
278
|
+
`items-center justify-center flex border-l ${outline && index !== 0 ? " border-(--border-color)" : "border-transparent"}
|
|
279
|
+
${column.align === "center" ? "justify-center text-center" : column.align === "right" ? "justify-end text-right" : "justify-start text-left"} gap-1 bg-(--bg-color) p-2 text-left`,
|
|
287
280
|
column.label?.class,
|
|
288
281
|
)}>
|
|
289
282
|
<span>{column.label?.name}</span>
|
|
@@ -309,7 +302,6 @@
|
|
|
309
302
|
{/if}
|
|
310
303
|
|
|
311
304
|
{#if body || buffer}
|
|
312
|
-
<!-- {@const isSliced = buffer.length - (dataBuffer.rowsAmmount ?? 10) > 0 ? buffer.length - ((dataBuffer.rowsAmmount ?? 10) % 2) !== 0 : false} -->
|
|
313
305
|
{@const rows =
|
|
314
306
|
type == "logger"
|
|
315
307
|
? buffer.filter(str => logType.includes(str.type)).slice(-(dataBuffer.rowsAmmount ?? 10))
|
|
@@ -319,19 +311,13 @@
|
|
|
319
311
|
<!-- Table Body с прокруткой -->
|
|
320
312
|
<div class="flex-1 overflow-y-auto bg-(--container-color)/50" bind:this={container} onscroll={handleScroll}>
|
|
321
313
|
<div class="grid min-w-0" style={`grid-template-columns: ${header.map(c => c.width || "minmax(0, 1fr)").join(" ")};`}>
|
|
322
|
-
{#each rows as row,
|
|
314
|
+
{#each rows as row, i (row)}
|
|
323
315
|
{#each header as column, j (column)}
|
|
324
316
|
<div
|
|
325
317
|
class="relative flex w-full min-w-0 items-center px-2 py-1 wrap-break-word
|
|
326
|
-
{
|
|
327
|
-
{column.align === 'center'
|
|
328
|
-
|
|
329
|
-
: column.align === 'right'
|
|
330
|
-
? 'flex justify-end text-right'
|
|
331
|
-
: 'flex justify-start text-left'}
|
|
332
|
-
border-t
|
|
333
|
-
{j !== 0 ? ' border-l ' : ''}
|
|
334
|
-
{outline ? 'border-(--border-color)' : 'border-transparent'} ">
|
|
318
|
+
{i % 2 ? 'bg-(--back-color)/40' : 'bg-[#edeef3] dark:bg-[#1f2a3a]'}
|
|
319
|
+
{column.align === 'center' ? 'justify-center text-center' : column.align === 'right' ? 'justify-end text-right' : 'justify-start text-left'}
|
|
320
|
+
border-t {j !== 0 ? ' border-l ' : ''} {outline ? 'border-(--border-color)' : 'border-transparent'}">
|
|
335
321
|
{#if column.action?.type == "buttons" && column.action?.buttons}
|
|
336
322
|
<div class="flex w-full flex-col gap-1">
|
|
337
323
|
{#each column.action?.buttons as button (button)}
|
|
@@ -346,24 +332,18 @@
|
|
|
346
332
|
</div>
|
|
347
333
|
{:else if column.action?.type == "select" && column.action?.select}
|
|
348
334
|
{@const options = Array.isArray(row[column.key])
|
|
349
|
-
? row[column.key].map((option: string | number) => ({
|
|
350
|
-
id: crypto.randomUUID(),
|
|
351
|
-
value: option,
|
|
352
|
-
name: option,
|
|
353
|
-
class: "",
|
|
354
|
-
disabled: false,
|
|
355
|
-
}))
|
|
335
|
+
? row[column.key].map((option: string | number) => ({ id: crypto.randomUUID(), value: option, name: option }))
|
|
356
336
|
: []}
|
|
357
337
|
|
|
358
338
|
<div class="relative w-full">
|
|
359
339
|
<button
|
|
360
|
-
class=
|
|
361
|
-
cursor-pointer hover:shadow-[0_0_6px_rgb(0_0_0_/0.25)]
|
|
362
|
-
onclick={() => (isDropdownOpen = isDropdownOpen ===
|
|
340
|
+
class="w-full rounded-2xl border border-(--blue-color) bg-(--back-color) p-1 text-center shadow-[0_0_3px_rgb(0_0_0_/0.25)] transition duration-200
|
|
341
|
+
cursor-pointer hover:shadow-[0_0_6px_rgb(0_0_0_/0.25)]"
|
|
342
|
+
onclick={() => (isDropdownOpen = isDropdownOpen?.x === j && isDropdownOpen.y === i ? null : { x: j, y: i })}>
|
|
363
343
|
{options[0]?.name || $t("common.select_tag")}
|
|
364
344
|
</button>
|
|
365
345
|
|
|
366
|
-
{#if isDropdownOpen ===
|
|
346
|
+
{#if isDropdownOpen?.x === j && isDropdownOpen.y === i}
|
|
367
347
|
<div
|
|
368
348
|
class="absolute top-full left-1/2 z-50 -translate-x-1/2 rounded-b-2xl shadow-[0_0_3px_rgb(0_0_0_/0.25)]"
|
|
369
349
|
style="width: calc(100% - 1.8rem);"
|
|
@@ -374,10 +354,10 @@
|
|
|
374
354
|
value={option?.value ? String(option.value) : ""}
|
|
375
355
|
class={twMerge(
|
|
376
356
|
`flex h-full w-full cursor-pointer items-center justify-center p-1 inset-shadow-[0_10px_10px_-15px_rgb(0_0_0_/0.5)] duration-250 hover:bg-(--field-color)! bg-(--back-color)
|
|
377
|
-
${option_index === options.length - 1 ? "rounded-b-2xl" : ""}
|
|
357
|
+
${option_index === options.length - 1 ? "rounded-b-2xl" : ""}`,
|
|
378
358
|
option.class,
|
|
379
359
|
)}
|
|
380
|
-
onclick={e => selectOption(
|
|
360
|
+
onclick={e => selectOption(i, column.key, option, e)}>
|
|
381
361
|
{option.name}
|
|
382
362
|
</button>
|
|
383
363
|
{/each}
|
|
@@ -436,12 +416,12 @@
|
|
|
436
416
|
onclick={e => {
|
|
437
417
|
e.preventDefault()
|
|
438
418
|
navigator.clipboard.writeText(row[column.key])
|
|
439
|
-
copiedCell = { x:
|
|
440
|
-
setTimeout(() => (copiedCell =
|
|
419
|
+
copiedCell = { x: j, y: i }
|
|
420
|
+
setTimeout(() => (copiedCell = null), 1000)
|
|
441
421
|
}}
|
|
442
422
|
aria-label="Копировать текст">
|
|
443
|
-
<div class="
|
|
444
|
-
{#if copiedCell
|
|
423
|
+
<div class="size-5 text-sm [&_svg]:h-full [&_svg]:max-h-full [&_svg]:w-full [&_svg]:max-w-full">
|
|
424
|
+
{#if copiedCell?.y === i && copiedCell.x === j}
|
|
445
425
|
<div
|
|
446
426
|
class="absolute top-1/2 right-3.5 -translate-y-1/2 transform rounded-md bg-(--green-color) px-1.5 py-1 shadow-lg"
|
|
447
427
|
transition:fade={{ duration: 200 }}>
|
|
@@ -470,8 +450,8 @@
|
|
|
470
450
|
{#if tooltip.show}
|
|
471
451
|
<div
|
|
472
452
|
class="fixed z-50 w-max max-w-[30%] rounded-md px-2 py-1 text-left text-sm whitespace-pre-wrap shadow-lg"
|
|
473
|
-
style="background: color-mix(in srgb, var(--yellow-color) 30%, var(--back-color)); transform: translateX(-50%);
|
|
474
|
-
|
|
453
|
+
style="background: color-mix(in srgb, var(--yellow-color) 30%, var(--back-color)); transform: translateX(-50%);
|
|
454
|
+
left: {tooltip.x + 10}px; top: {tooltip.y + 10}px;"
|
|
475
455
|
transition:fly={{ y: 10, duration: 200 }}
|
|
476
456
|
role="tooltip">
|
|
477
457
|
{@html tooltip.text}
|
package/dist/Tabs/Tabs.svelte
CHANGED
|
@@ -1,27 +1,26 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import type { ITabsProps } from
|
|
3
|
-
import {
|
|
4
|
-
import { twMerge } from 'tailwind-merge'
|
|
2
|
+
import type { ITabsProps } from "../types"
|
|
3
|
+
import { twMerge } from "tailwind-merge"
|
|
5
4
|
|
|
6
5
|
let {
|
|
7
6
|
id = crypto.randomUUID(),
|
|
8
|
-
wrapperClass =
|
|
7
|
+
wrapperClass = "",
|
|
9
8
|
size = { width: 12, height: 6 },
|
|
10
9
|
activeTab = 0,
|
|
11
10
|
items = [
|
|
12
11
|
{
|
|
13
|
-
name:
|
|
12
|
+
name: "tab 1",
|
|
14
13
|
icon: '<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24"\r\n ><path\r\n fill="none"\r\n stroke="currentColor"\r\n stroke-linecap="round"\r\n stroke-linejoin="round"\r\n stroke-width="1.5"\r\n d="M14.44 5.78L4.198 16.02a2 2 0 0 0-.565 1.125l-.553 3.774l3.775-.553A2 2 0 0 0 7.98 19.8L18.22 9.56m-3.78-3.78l2.229-2.23a1.6 1.6 0 0 1 2.263 0l1.518 1.518a1.6 1.6 0 0 1 0 2.263l-2.23 2.23M14.44 5.78l3.78 3.78"\r\n /></svg\r\n>\r\n',
|
|
15
|
-
class:
|
|
14
|
+
class: "",
|
|
16
15
|
},
|
|
17
|
-
{ name:
|
|
16
|
+
{ name: "tab 2", icon: "", class: "bg-red" },
|
|
18
17
|
],
|
|
19
18
|
children,
|
|
20
19
|
apiArray = [],
|
|
21
20
|
Components,
|
|
22
21
|
}: ITabsProps = $props()
|
|
23
22
|
|
|
24
|
-
const isCol = $derived(!!items.find(
|
|
23
|
+
const isCol = $derived(!!items.find(item => item.class?.startsWith("flex-col")))
|
|
25
24
|
|
|
26
25
|
let currentTabIndex: number = $derived(activeTab)
|
|
27
26
|
</script>
|
|
@@ -29,26 +28,24 @@
|
|
|
29
28
|
<div id={`${id}-${crypto.randomUUID().slice(0, 6)}`} class="w-full h-full flex flex-col rounded-2xl bg-(--back-color) overflow-hidden">
|
|
30
29
|
<!-- Вкладки -->
|
|
31
30
|
<div
|
|
32
|
-
class="{twMerge(`bg-blue z-
|
|
33
|
-
bg-(--bg-color)"
|
|
34
|
-
>
|
|
31
|
+
class="{twMerge(`bg-blue z-40 flex h-fit items-center rounded-t-2xl overflow-x-auto px-1`, wrapperClass)}
|
|
32
|
+
bg-(--bg-color)">
|
|
35
33
|
{#each items as item, index}
|
|
36
34
|
<button
|
|
37
35
|
class={twMerge(
|
|
38
|
-
`tab mt-1 flex min-w-fit cursor-pointer items-center justify-center gap-0 self-end rounded-t-2xl px-5 py-2.5 ${isCol && items.find(
|
|
36
|
+
`tab mt-1 flex min-w-fit cursor-pointer items-center justify-center gap-0 self-end rounded-t-2xl px-5 py-2.5 ${isCol && items.find(item => item.icon) ? "h-20" : "gap-2"}`,
|
|
39
37
|
item.class,
|
|
40
|
-
index === currentTabIndex ? twMerge(
|
|
38
|
+
index === currentTabIndex ? twMerge("bg-(--back-color) text-blue-500", item.class) : "bg-(--bg-color) text-gray-500",
|
|
41
39
|
)}
|
|
42
40
|
style="width: {item.class
|
|
43
41
|
?.split(' ')
|
|
44
42
|
.find((cls: string) => cls.startsWith('w-'))
|
|
45
43
|
?.replace('w-[', '')
|
|
46
44
|
.slice(0, -1)};"
|
|
47
|
-
onclick={() => (currentTabIndex = index)}
|
|
48
|
-
>
|
|
45
|
+
onclick={() => (currentTabIndex = index)}>
|
|
49
46
|
{#if item?.icon}
|
|
50
47
|
<span class="flex h-7 w-7 items-center justify-center overflow-visible [&_svg]:h-full [&_svg]:max-h-full [&_svg]:w-full [&_svg]:max-w-full">
|
|
51
|
-
{#if typeof item.icon ===
|
|
48
|
+
{#if typeof item.icon === "string"}
|
|
52
49
|
{@html item.icon}
|
|
53
50
|
{:else}
|
|
54
51
|
{@const IconComponent = item.icon}
|
|
@@ -61,22 +58,20 @@
|
|
|
61
58
|
{/if}
|
|
62
59
|
</button>
|
|
63
60
|
<span
|
|
64
|
-
class="{isCol && items.find(
|
|
61
|
+
class="{isCol && items.find(item => item.icon) ? 'h-9' : 'h-4'} w-0 border border-l {index !== items.length - 1 &&
|
|
65
62
|
index !== currentTabIndex &&
|
|
66
63
|
index !== currentTabIndex - 1
|
|
67
64
|
? 'border-gray-500'
|
|
68
|
-
: 'border-(--bg-color)'}"
|
|
69
|
-
></span>
|
|
65
|
+
: 'border-(--bg-color)'}"></span>
|
|
70
66
|
{/each}
|
|
71
67
|
</div>
|
|
72
68
|
|
|
73
69
|
<!-- Контент вкладки -->
|
|
74
70
|
<div
|
|
75
71
|
class="grid flex-1 overflow-y-scroll w-full gap-2 rounded-2xl bg-(--back-color) p-4"
|
|
76
|
-
style="grid-template-columns: repeat({size.width || 1}, minmax(0, 1fr)); grid-template-rows: repeat({size.height || 1}, auto);"
|
|
77
|
-
>
|
|
72
|
+
style="grid-template-columns: repeat({size.width || 1}, minmax(0, 1fr)); grid-template-rows: repeat({size.height || 1}, auto);">
|
|
78
73
|
{#if Components}
|
|
79
|
-
{#each (apiArray ?? []).filter(
|
|
74
|
+
{#each (apiArray ?? []).filter(c => c.id.endsWith(`${currentTabIndex}`)) as comp}
|
|
80
75
|
{@render Components(comp, false)}
|
|
81
76
|
{/each}
|
|
82
77
|
{:else if children}
|