poe-svelte-ui-lib 1.6.1 → 1.6.3
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/Input/Input.svelte +68 -77
- package/dist/Input/Input.svelte.d.ts +1 -1
- package/dist/Table/Table.svelte +154 -118
- package/dist/Table/Table.svelte.d.ts +1 -1
- package/dist/Table/TableProps.svelte +442 -399
- package/dist/Table/TableProps.svelte.d.ts +1 -1
- package/dist/Tabs/TabsProps.svelte +18 -16
- package/dist/libIcons/ButtonAdd.svelte +2 -7
- package/dist/libIcons/ButtonRemove.svelte +8 -0
- package/dist/libIcons/ButtonRemove.svelte.d.ts +18 -0
- package/dist/locales/translations.js +221 -218
- package/dist/options.d.ts +5 -0
- package/dist/options.js +161 -157
- package/dist/types.d.ts +30 -23
- package/dist/types.js +1 -1
- package/package.json +2 -2
package/dist/Input/Input.svelte
CHANGED
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
<!-- $lib/ElementsUI/Input.svelte -->
|
|
2
2
|
<script lang="ts">
|
|
3
|
-
import { fade, fly } from
|
|
4
|
-
import type { IInputProps } from
|
|
5
|
-
import { twMerge } from
|
|
3
|
+
import { fade, fly } from "svelte/transition"
|
|
4
|
+
import type { IInputProps } from "../types"
|
|
5
|
+
import { twMerge } from "tailwind-merge"
|
|
6
6
|
|
|
7
7
|
let {
|
|
8
8
|
id = crypto.randomUUID(),
|
|
9
|
-
wrapperClass =
|
|
10
|
-
label = { name:
|
|
9
|
+
wrapperClass = "",
|
|
10
|
+
label = { name: "", class: "" },
|
|
11
11
|
disabled = false,
|
|
12
12
|
readonly = false,
|
|
13
13
|
value = $bindable(),
|
|
14
|
-
type =
|
|
15
|
-
placeholder =
|
|
16
|
-
componentClass =
|
|
14
|
+
type = "text",
|
|
15
|
+
placeholder = "",
|
|
16
|
+
componentClass = "",
|
|
17
17
|
maxlength = 100,
|
|
18
18
|
textareaRows = 3,
|
|
19
19
|
isValid = $bindable(true),
|
|
20
20
|
number = { minNum: -1000000, maxNum: 1000000, step: 1 },
|
|
21
|
-
help = { info:
|
|
21
|
+
help = { info: "", autocomplete: "off", copyButton: false, regExp: "^[\\s\\S]*$" },
|
|
22
22
|
onUpdate = () => {},
|
|
23
23
|
}: IInputProps = $props()
|
|
24
24
|
|
|
@@ -26,11 +26,11 @@
|
|
|
26
26
|
let showInfo = $state(false)
|
|
27
27
|
let isCopied = $state(false)
|
|
28
28
|
|
|
29
|
-
$effect(() => {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
})
|
|
29
|
+
// $effect(() => {
|
|
30
|
+
// if (type === "number") {
|
|
31
|
+
// if (value === undefined || value === null || value === "") value = number.minNum
|
|
32
|
+
// }
|
|
33
|
+
// })
|
|
34
34
|
|
|
35
35
|
/* Обработка регулярного выражения */
|
|
36
36
|
const parseRegExp = (pattern: string | RegExp): RegExp => {
|
|
@@ -38,14 +38,15 @@
|
|
|
38
38
|
const match = pattern.match(/^\/(.*)\/([gimsuy]*)$/)
|
|
39
39
|
return match ? new RegExp(match[1], match[2]) : new RegExp(pattern)
|
|
40
40
|
}
|
|
41
|
-
let RegExpObj = $derived(() => parseRegExp(help.regExp ??
|
|
41
|
+
let RegExpObj = $derived(() => parseRegExp(help.regExp ?? ""))
|
|
42
|
+
|
|
42
43
|
$effect(() => {
|
|
43
|
-
isValid = RegExpObj().test(typeof value ===
|
|
44
|
+
isValid = RegExpObj().test(typeof value === "string" ? value : String(value))
|
|
44
45
|
})
|
|
45
46
|
|
|
46
47
|
const handleInputChange = (value: string | number) => {
|
|
47
|
-
if (type ===
|
|
48
|
-
const numValue = typeof value ===
|
|
48
|
+
if (type === "number") {
|
|
49
|
+
const numValue = typeof value === "string" ? parseFloat(value.replace(",", ".")) : Number(value)
|
|
49
50
|
if (!isNaN(numValue)) onUpdate?.(numValue)
|
|
50
51
|
else onUpdate?.(value as string)
|
|
51
52
|
} else {
|
|
@@ -53,8 +54,16 @@
|
|
|
53
54
|
}
|
|
54
55
|
}
|
|
55
56
|
|
|
57
|
+
const handleKeyDown = (e: KeyboardEvent) => {
|
|
58
|
+
if (type === "number") {
|
|
59
|
+
if (e.key === ".") {
|
|
60
|
+
e.preventDefault()
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
56
65
|
$effect(() => {
|
|
57
|
-
if (type ===
|
|
66
|
+
if (type === "number" && typeof value == "number") {
|
|
58
67
|
value = roundToClean(value)
|
|
59
68
|
}
|
|
60
69
|
})
|
|
@@ -72,23 +81,23 @@
|
|
|
72
81
|
}
|
|
73
82
|
</script>
|
|
74
83
|
|
|
75
|
-
<div class={twMerge(`bg-max ${type ===
|
|
84
|
+
<div class={twMerge(`bg-max ${type === "text-area" ? "h-full" : ""} relative flex w-full flex-col px-1 items-center`, wrapperClass)}>
|
|
76
85
|
{#if label.name}
|
|
77
86
|
<h5 class={twMerge(`w-full px-4 text-center`, label.class)}>{label.name}</h5>
|
|
78
87
|
{/if}
|
|
79
88
|
|
|
80
89
|
<div class="relative flex w-full items-center {type === 'text-area' ? 'h-full' : ''}">
|
|
81
|
-
{#if type ===
|
|
90
|
+
{#if type === "text" || type === "password" || type === "number"}
|
|
82
91
|
<input
|
|
83
92
|
bind:value
|
|
84
93
|
class={twMerge(
|
|
85
94
|
`w-full rounded-2xl border px-4 py-1 text-center shadow-[0_0_3px_rgb(0_0_0_/0.25)] transition duration-200
|
|
86
95
|
outline-none focus:shadow-[0_0_6px_var(--blue-color)] focus:border-(--blue-color) [&::-webkit-inner-spin-button]:hidden [&::-webkit-outer-spin-button]:hidden
|
|
87
|
-
${isValid ?
|
|
88
|
-
${disabled ?
|
|
89
|
-
${readonly ?
|
|
90
|
-
${help?.info ?
|
|
91
|
-
${help.copyButton || type ===
|
|
96
|
+
${isValid ? "border-(--bg-color)" : "border-red-400 shadow-[0_0_6px_var(--red-color)] focus:shadow-[0_0_6px_var(--red-color)] focus:border-red-400"}
|
|
97
|
+
${disabled ? "opacity-50" : "hover:shadow-[0_0_6px_rgb(0_0_0_/0.25)]"}
|
|
98
|
+
${readonly ? "" : "hover:shadow-[0_0_6px_rgb(0_0_0_/0.25)]"}
|
|
99
|
+
${help?.info ? "pl-8" : ""}
|
|
100
|
+
${help.copyButton || type === "password" || (type === "number" && !readonly) ? "pr-8" : ""}`,
|
|
92
101
|
componentClass,
|
|
93
102
|
)}
|
|
94
103
|
style="background: color-mix(in srgb, var(--bg-color), var(--back-color) 70%);"
|
|
@@ -96,25 +105,25 @@
|
|
|
96
105
|
{placeholder}
|
|
97
106
|
{disabled}
|
|
98
107
|
autocomplete={help?.autocomplete}
|
|
99
|
-
oninput={
|
|
100
|
-
|
|
108
|
+
oninput={e => handleInputChange((e.currentTarget as HTMLInputElement).value)}
|
|
109
|
+
onkeydown={handleKeyDown}
|
|
110
|
+
type={type === "password" ? (showPassword ? "text" : "password") : type === "number" ? "number" : "text"}
|
|
101
111
|
{maxlength}
|
|
102
112
|
min={number?.minNum}
|
|
103
113
|
max={number?.maxNum}
|
|
104
114
|
step={number?.step}
|
|
105
|
-
{readonly}
|
|
106
|
-
|
|
107
|
-
{:else if type === 'text-area'}
|
|
115
|
+
{readonly} />
|
|
116
|
+
{:else if type === "text-area"}
|
|
108
117
|
<textarea
|
|
109
118
|
bind:value
|
|
110
119
|
class={twMerge(
|
|
111
120
|
`h-full w-full resize-y rounded-2xl border border-(--border-color) px-2 py-1 text-center shadow-[0_0_3px_rgb(0_0_0_/0.25)] transition
|
|
112
121
|
duration-200 outline-none focus:border-blue-400
|
|
113
|
-
${isValid ?
|
|
114
|
-
${disabled ?
|
|
115
|
-
${readonly ?
|
|
116
|
-
${help?.info ?
|
|
117
|
-
${help.copyButton ?
|
|
122
|
+
${isValid ? "border-(--bg-color)" : "border-red-400 shadow-[0_0_6px_var(--red-color)] focus:shadow-[0_0_6px_var(--red-color)] focus:border-red-400"}
|
|
123
|
+
${disabled ? "cursor-not-allowed opacity-50" : "hover:shadow-[0_0_6px_rgb(0_0_0_/0.25)]"}
|
|
124
|
+
${readonly ? "" : "hover:shadow-[0_0_6px_rgb(0_0_0_/0.25)]"}
|
|
125
|
+
${help?.info ? "pl-8" : ""}
|
|
126
|
+
${help.copyButton ? "pr-8" : ""}`,
|
|
118
127
|
componentClass,
|
|
119
128
|
)}
|
|
120
129
|
style="background: color-mix(in srgb, var(--bg-color), var(--back-color) 70%);"
|
|
@@ -124,63 +133,55 @@
|
|
|
124
133
|
rows={textareaRows}
|
|
125
134
|
{placeholder}
|
|
126
135
|
{readonly}
|
|
127
|
-
oninput={
|
|
128
|
-
></textarea>
|
|
136
|
+
oninput={e => handleInputChange((e.currentTarget as HTMLTextAreaElement).value)}></textarea>
|
|
129
137
|
{/if}
|
|
130
138
|
|
|
131
|
-
{#if type ===
|
|
139
|
+
{#if type === "password" && !disabled}
|
|
132
140
|
<button
|
|
133
141
|
type="button"
|
|
134
142
|
class="absolute right-2 flex cursor-pointer border-none bg-transparent"
|
|
135
143
|
onclick={() => (showPassword = !showPassword)}
|
|
136
|
-
aria-label={showPassword ?
|
|
137
|
-
>
|
|
144
|
+
aria-label={showPassword ? "Скрыть пароль" : "Показать пароль"}>
|
|
138
145
|
{#if showPassword}
|
|
139
146
|
<svg xmlns="http://www.w3.org/2000/svg" width="1.5rem" height="1.5rem" viewBox="0 0 24 24"
|
|
140
147
|
><g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"
|
|
141
148
|
><path d="M15 12a3 3 0 1 1-6 0a3 3 0 0 1 6 0" /><path
|
|
142
|
-
d="M2 12c1.6-4.097 5.336-7 10-7s8.4 2.903 10 7c-1.6 4.097-5.336 7-10 7s-8.4-2.903-10-7"
|
|
143
|
-
|
|
144
|
-
></svg
|
|
145
|
-
>
|
|
149
|
+
d="M2 12c1.6-4.097 5.336-7 10-7s8.4 2.903 10 7c-1.6 4.097-5.336 7-10 7s-8.4-2.903-10-7" /></g
|
|
150
|
+
></svg>
|
|
146
151
|
{:else}
|
|
147
152
|
<svg xmlns="http://www.w3.org/2000/svg" width="1.5rem" height="1.5rem" viewBox="0 0 24 24"
|
|
148
153
|
><g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"
|
|
149
154
|
><path
|
|
150
155
|
stroke-linejoin="round"
|
|
151
|
-
d="M10.73 5.073A11 11 0 0 1 12 5c4.664 0 8.4 2.903 10 7a11.6 11.6 0 0 1-1.555 2.788M6.52 6.519C4.48 7.764 2.9 9.693 2 12c1.6 4.097 5.336 7 10 7a10.44 10.44 0 0 0 5.48-1.52m-7.6-7.6a3 3 0 1 0 4.243 4.243"
|
|
152
|
-
|
|
153
|
-
></svg
|
|
154
|
-
>
|
|
156
|
+
d="M10.73 5.073A11 11 0 0 1 12 5c4.664 0 8.4 2.903 10 7a11.6 11.6 0 0 1-1.555 2.788M6.52 6.519C4.48 7.764 2.9 9.693 2 12c1.6 4.097 5.336 7 10 7a10.44 10.44 0 0 0 5.48-1.52m-7.6-7.6a3 3 0 1 0 4.243 4.243" /><path
|
|
157
|
+
d="m4 4l16 16" /></g
|
|
158
|
+
></svg>
|
|
155
159
|
{/if}
|
|
156
160
|
</button>
|
|
157
161
|
{/if}
|
|
158
162
|
|
|
159
|
-
{#if help.copyButton && (type ===
|
|
163
|
+
{#if help.copyButton && (type === "text" || type === "text-area") && !disabled}
|
|
160
164
|
<button
|
|
161
165
|
class="absolute right-3 flex border-none bg-transparent {type === 'text-area' ? 'top-2' : ''} cursor-pointer"
|
|
162
|
-
onclick={
|
|
166
|
+
onclick={e => {
|
|
163
167
|
e.preventDefault()
|
|
164
168
|
navigator.clipboard.writeText(value as string)
|
|
165
169
|
isCopied = true
|
|
166
170
|
setTimeout(() => (isCopied = false), 1000)
|
|
167
171
|
}}
|
|
168
|
-
aria-label="Копировать текст"
|
|
169
|
-
>
|
|
172
|
+
aria-label="Копировать текст">
|
|
170
173
|
<div class=" size-5 text-sm [&_svg]:h-full [&_svg]:max-h-full [&_svg]:w-full [&_svg]:max-w-full">
|
|
171
174
|
{#if isCopied}
|
|
172
175
|
<div
|
|
173
176
|
class="right-1..5 absolute top-1/2 -translate-y-1/2 transform rounded-md bg-(--green-color) px-1.5 py-1 shadow-lg"
|
|
174
|
-
transition:fade={{ duration: 200 }}
|
|
175
|
-
>
|
|
177
|
+
transition:fade={{ duration: 200 }}>
|
|
176
178
|
✓
|
|
177
179
|
</div>
|
|
178
180
|
{:else}
|
|
179
181
|
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
|
|
180
182
|
<g fill="none" stroke="currentColor" stroke-width="1.5">
|
|
181
183
|
<path
|
|
182
|
-
d="M6 11c0-2.828 0-4.243.879-5.121C7.757 5 9.172 5 12 5h3c2.828 0 4.243 0 5.121.879C21 6.757 21 8.172 21 11v5c0 2.828 0 4.243-.879 5.121C19.243 22 17.828 22 15 22h-3c-2.828 0-4.243 0-5.121-.879C6 20.243 6 18.828 6 16z"
|
|
183
|
-
/>
|
|
184
|
+
d="M6 11c0-2.828 0-4.243.879-5.121C7.757 5 9.172 5 12 5h3c2.828 0 4.243 0 5.121.879C21 6.757 21 8.172 21 11v5c0 2.828 0 4.243-.879 5.121C19.243 22 17.828 22 15 22h-3c-2.828 0-4.243 0-5.121-.879C6 20.243 6 18.828 6 16z" />
|
|
184
185
|
<path d="M6 19a3 3 0 0 1-3-3v-6c0-3.771 0-5.657 1.172-6.828S7.229 2 11 2h4a3 3 0 0 1 3 3" />
|
|
185
186
|
</g>
|
|
186
187
|
</svg>
|
|
@@ -189,12 +190,12 @@
|
|
|
189
190
|
</button>
|
|
190
191
|
{/if}
|
|
191
192
|
|
|
192
|
-
{#if type ===
|
|
193
|
+
{#if type === "number" && !readonly && !disabled}
|
|
193
194
|
<div class="absolute right-0 flex h-full w-8 flex-col items-center justify-center rounded-r-2xl border-l border-(--border-color)">
|
|
194
195
|
<button
|
|
195
196
|
class="flex h-1/2 w-full items-center rounded-tr-2xl border-b border-(--border-color) pl-2 transition-colors duration-150 hover:bg-(--gray-color)/30 active:bg-(--gray-color)/10"
|
|
196
197
|
onclick={() => {
|
|
197
|
-
if (!number.maxNum || !number.step) return
|
|
198
|
+
if (!number.maxNum || !number.step || !value) return
|
|
198
199
|
if (Number(value) + number.step >= number.maxNum) {
|
|
199
200
|
value = number.maxNum
|
|
200
201
|
onUpdate(value as number)
|
|
@@ -203,13 +204,12 @@
|
|
|
203
204
|
value = Number(value) + (number.step ?? 1)
|
|
204
205
|
onUpdate(value as number)
|
|
205
206
|
}}
|
|
206
|
-
aria-label="Увеличить">+</button
|
|
207
|
-
>
|
|
207
|
+
aria-label="Увеличить">+</button>
|
|
208
208
|
|
|
209
209
|
<button
|
|
210
210
|
class="flex h-1/2 w-full items-center rounded-br-2xl pl-2 transition-colors duration-150 hover:bg-(--gray-color)/30 active:bg-(--gray-color)/10"
|
|
211
211
|
onclick={() => {
|
|
212
|
-
if (number.minNum
|
|
212
|
+
if (!number.minNum || !number.step || !value) return
|
|
213
213
|
if (Number(value) - number.step <= number.minNum) {
|
|
214
214
|
value = number.minNum
|
|
215
215
|
onUpdate(value as number)
|
|
@@ -218,36 +218,27 @@
|
|
|
218
218
|
value = Number(value) - (number.step ?? 1)
|
|
219
219
|
onUpdate(value as number)
|
|
220
220
|
}}
|
|
221
|
-
aria-label="Уменьшить">−</button
|
|
222
|
-
>
|
|
221
|
+
aria-label="Уменьшить">−</button>
|
|
223
222
|
</div>
|
|
224
223
|
{/if}
|
|
225
224
|
|
|
226
225
|
{#if help.info}
|
|
227
226
|
<button
|
|
228
227
|
type="button"
|
|
229
|
-
class="button-info absolute left-2 flex border-none bg-transparent {type === 'text-area' ? 'top-2' : ''} {disabled
|
|
230
|
-
? 'opacity-50'
|
|
231
|
-
: 'cursor-pointer'}"
|
|
228
|
+
class="button-info absolute left-2 flex border-none bg-transparent {type === 'text-area' ? 'top-2' : ''} {disabled ? 'opacity-50' : 'cursor-pointer'}"
|
|
232
229
|
onmouseenter={() => (showInfo = true)}
|
|
233
230
|
onmouseleave={() => (showInfo = false)}
|
|
234
|
-
aria-label={showInfo ?
|
|
235
|
-
>
|
|
231
|
+
aria-label={showInfo ? "Скрыть инфо" : "Показать инфо"}>
|
|
236
232
|
<svg xmlns="http://www.w3.org/2000/svg" width="1.5rem" height="1.5rem" viewBox="0 0 24 24"
|
|
237
233
|
><g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
|
|
238
|
-
><circle cx="12" cy="12" r="10" stroke-width="1.3" /><path stroke-width="1.5" d="M12 16v-4.5" /><path
|
|
239
|
-
|
|
240
|
-
d="M12 8.012v-.01"
|
|
241
|
-
/></g
|
|
242
|
-
></svg
|
|
243
|
-
>
|
|
234
|
+
><circle cx="12" cy="12" r="10" stroke-width="1.3" /><path stroke-width="1.5" d="M12 16v-4.5" /><path stroke-width="1.8" d="M12 8.012v-.01" /></g
|
|
235
|
+
></svg>
|
|
244
236
|
</button>
|
|
245
237
|
|
|
246
238
|
{#if showInfo}
|
|
247
239
|
<div
|
|
248
240
|
transition:fly={{ x: -15, duration: 250 }}
|
|
249
|
-
class="absolute top-5 left-10 z-50 w-auto -translate-y-1/2 rounded bg-(--container-color) px-2 py-1 shadow-lg"
|
|
250
|
-
>
|
|
241
|
+
class="absolute top-5 left-10 z-50 w-auto -translate-y-1/2 rounded bg-(--container-color) px-2 py-1 shadow-lg">
|
|
251
242
|
{help?.info}
|
|
252
243
|
</div>
|
|
253
244
|
{/if}
|