poe-svelte-ui-lib 1.4.8 → 1.5.1
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/Table/Table.svelte +226 -106
- package/dist/Table/Table.svelte.d.ts +1 -1
- package/dist/Table/TableProps.svelte +68 -31
- package/dist/locales/translations.js +5 -0
- package/dist/options.d.ts +5 -0
- package/dist/options.js +4 -0
- package/dist/types.d.ts +5 -2
- package/package.json +4 -4
package/dist/Table/Table.svelte
CHANGED
|
@@ -10,9 +10,12 @@
|
|
|
10
10
|
id = crypto.randomUUID(),
|
|
11
11
|
wrapperClass = '',
|
|
12
12
|
label = { name: '', class: '' },
|
|
13
|
-
body =
|
|
13
|
+
body = $bindable(),
|
|
14
14
|
header = [],
|
|
15
15
|
footer = '',
|
|
16
|
+
stashData = false,
|
|
17
|
+
type = 'table',
|
|
18
|
+
rowsAmmount = 10,
|
|
16
19
|
outline = false,
|
|
17
20
|
cursor = null,
|
|
18
21
|
loader,
|
|
@@ -22,6 +25,8 @@
|
|
|
22
25
|
onClick,
|
|
23
26
|
}: ITableProps<any> = $props()
|
|
24
27
|
|
|
28
|
+
let dataBuffer: any[] = $state([])
|
|
29
|
+
|
|
25
30
|
/* Сортировка */
|
|
26
31
|
let sortState: {
|
|
27
32
|
key: string | null
|
|
@@ -33,6 +38,13 @@
|
|
|
33
38
|
|
|
34
39
|
let isAutoscroll = $state(false)
|
|
35
40
|
|
|
41
|
+
const logTypeOptions = [
|
|
42
|
+
{ id: crypto.randomUUID(), name: 'Error', value: 'error', color: 'bg-(--red-color)' },
|
|
43
|
+
{ id: crypto.randomUUID(), name: 'Warning', value: 'warning', color: 'bg-(--yellow-color)' },
|
|
44
|
+
{ id: crypto.randomUUID(), name: 'Info', value: 'info', color: 'bg-(--gray-color)' },
|
|
45
|
+
]
|
|
46
|
+
let logType = $state(['error', 'warning'])
|
|
47
|
+
|
|
36
48
|
/* Сортировка столбцов */
|
|
37
49
|
const sortRows = (key: string) => {
|
|
38
50
|
if (sortState.key === key) {
|
|
@@ -87,8 +99,9 @@
|
|
|
87
99
|
container.scrollTop = container.scrollHeight
|
|
88
100
|
}
|
|
89
101
|
}
|
|
102
|
+
|
|
90
103
|
$effect(() => {
|
|
91
|
-
if (
|
|
104
|
+
if (autoscroll && dataBuffer && dataBuffer.length > 0) {
|
|
92
105
|
scrollToBottom()
|
|
93
106
|
}
|
|
94
107
|
})
|
|
@@ -141,12 +154,78 @@
|
|
|
141
154
|
return !!src
|
|
142
155
|
}
|
|
143
156
|
|
|
157
|
+
$effect(() => {
|
|
158
|
+
if (body && type == 'logger') {
|
|
159
|
+
dataBuffer = [
|
|
160
|
+
...dataBuffer,
|
|
161
|
+
{
|
|
162
|
+
type: Object.entries(body)[0][1] as string,
|
|
163
|
+
color: `<div class='size-6 rounded-full ${logTypeOptions.find((o) => o.value == body.logLevel)?.color}'></div>`,
|
|
164
|
+
data: Object.entries(body)[1][1] as string,
|
|
165
|
+
},
|
|
166
|
+
]
|
|
167
|
+
|
|
168
|
+
if (dataBuffer.length > rowsAmmount * 5) {
|
|
169
|
+
dataBuffer = dataBuffer.slice(-(rowsAmmount * 5))
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
body = null
|
|
173
|
+
}
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
$effect(() => {
|
|
177
|
+
if (body && stashData && type == 'table') {
|
|
178
|
+
dataBuffer = [...dataBuffer, body]
|
|
179
|
+
if (dataBuffer.length > rowsAmmount) {
|
|
180
|
+
dataBuffer = dataBuffer.slice(-rowsAmmount)
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
body = null
|
|
184
|
+
}
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
$effect(() => {
|
|
188
|
+
const currentType = type
|
|
189
|
+
if (type === 'logger') {
|
|
190
|
+
header = [
|
|
191
|
+
{
|
|
192
|
+
key: 'color',
|
|
193
|
+
label: { name: 'Type' },
|
|
194
|
+
width: '3rem',
|
|
195
|
+
} as ITableHeader<any>,
|
|
196
|
+
{
|
|
197
|
+
key: 'data',
|
|
198
|
+
label: { name: 'Data' },
|
|
199
|
+
width: 'calc(100% - 3rem)',
|
|
200
|
+
} as ITableHeader<any>,
|
|
201
|
+
]
|
|
202
|
+
}
|
|
203
|
+
return () => {
|
|
204
|
+
dataBuffer = []
|
|
205
|
+
}
|
|
206
|
+
})
|
|
207
|
+
|
|
144
208
|
onMount(() => {
|
|
145
209
|
if (autoscroll) {
|
|
146
210
|
container?.addEventListener('scroll', handleAutoScroll)
|
|
147
211
|
scrollToBottom()
|
|
148
212
|
}
|
|
149
213
|
|
|
214
|
+
if (type === 'logger') {
|
|
215
|
+
header = [
|
|
216
|
+
{
|
|
217
|
+
key: 'color',
|
|
218
|
+
label: { name: 'Type' },
|
|
219
|
+
width: '3rem',
|
|
220
|
+
} as ITableHeader<any>,
|
|
221
|
+
{
|
|
222
|
+
key: 'data',
|
|
223
|
+
label: { name: 'Data' },
|
|
224
|
+
width: 'calc(100% - 3rem)',
|
|
225
|
+
} as ITableHeader<any>,
|
|
226
|
+
]
|
|
227
|
+
}
|
|
228
|
+
|
|
150
229
|
return () => {
|
|
151
230
|
if (autoscroll) {
|
|
152
231
|
container?.removeEventListener('scroll', handleAutoScroll)
|
|
@@ -155,13 +234,51 @@
|
|
|
155
234
|
})
|
|
156
235
|
</script>
|
|
157
236
|
|
|
158
|
-
<div
|
|
237
|
+
<div
|
|
238
|
+
id={`${id}-${crypto.randomUUID().slice(0, 6)}`}
|
|
239
|
+
class={twMerge(`bg-blue flex h-full w-full gap-2 items-center flex-col overflow-hidden`, wrapperClass)}
|
|
240
|
+
>
|
|
159
241
|
{#if label.name}
|
|
160
242
|
<h5 class={twMerge(`w-full px-4 text-center`, label.class)}>{label.name}</h5>
|
|
161
243
|
{/if}
|
|
162
244
|
|
|
245
|
+
{#if type == 'logger'}
|
|
246
|
+
<div id={`${id}-${crypto.randomUUID().slice(0, 6)}`} class="flex w-[50%] justify-center rounded-full">
|
|
247
|
+
{#each logTypeOptions as option, index}
|
|
248
|
+
<button
|
|
249
|
+
id={crypto.randomUUID()}
|
|
250
|
+
class={twMerge(`m-0 inline-block min-w-0 flex-1 cursor-pointer items-center px-2 py-1 font-semibold shadow-sm transition-all duration-300
|
|
251
|
+
select-none hover:shadow-md
|
|
252
|
+
${
|
|
253
|
+
logType.includes(option.value) && logType !== null
|
|
254
|
+
? 'z-10 py-1 shadow-[0_0_10px_var(--shadow-color)] hover:shadow-[0_0_15px_var(--shadow-color)]'
|
|
255
|
+
: ''
|
|
256
|
+
}
|
|
257
|
+
${logTypeOptions.length > 0 && index === 0 ? 'rounded-l-2xl' : ''} ${
|
|
258
|
+
index === logTypeOptions.length - 1 ? 'rounded-r-2xl' : ''
|
|
259
|
+
} ${option.color}`)}
|
|
260
|
+
onclick={() => {
|
|
261
|
+
if (logType.includes(option.value)) {
|
|
262
|
+
logType = logType.filter((type) => type !== option.value)
|
|
263
|
+
} else {
|
|
264
|
+
logType.push(option.value)
|
|
265
|
+
}
|
|
266
|
+
}}
|
|
267
|
+
>
|
|
268
|
+
<span class="flex flex-row items-center justify-center gap-4">
|
|
269
|
+
{#if option}
|
|
270
|
+
<div class="flex-1">
|
|
271
|
+
{option.name}
|
|
272
|
+
</div>
|
|
273
|
+
{/if}
|
|
274
|
+
</span>
|
|
275
|
+
</button>
|
|
276
|
+
{/each}
|
|
277
|
+
</div>
|
|
278
|
+
{/if}
|
|
279
|
+
|
|
163
280
|
<div
|
|
164
|
-
class="flex h-full flex-col overflow-hidden rounded-xl border shadow-sm transition duration-200 hover:shadow-md {outline
|
|
281
|
+
class="flex h-full w-full flex-col overflow-hidden rounded-xl border shadow-sm transition duration-200 hover:shadow-md {outline
|
|
165
282
|
? ' border-(--border-color)'
|
|
166
283
|
: 'border-transparent'} "
|
|
167
284
|
>
|
|
@@ -193,126 +310,129 @@
|
|
|
193
310
|
{/each}
|
|
194
311
|
</div>
|
|
195
312
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
313
|
+
{#if body || dataBuffer}
|
|
314
|
+
{@const rows = type == 'logger' ? dataBuffer.filter((str) => logType.includes(str.type)).slice(-rowsAmmount) : stashData ? dataBuffer : body}
|
|
315
|
+
<!-- Table Body с прокруткой -->
|
|
316
|
+
<div class="flex-1 overflow-y-auto bg-(--container-color)/50" bind:this={container} onscroll={handleScroll}>
|
|
317
|
+
<div class="grid min-w-0" style={`grid-template-columns: ${header.map((c) => c.width || 'minmax(0, 1fr)').join(' ')};`}>
|
|
318
|
+
{#each rows as row, index (row)}
|
|
319
|
+
{#each header as column, j (column)}
|
|
320
|
+
<div
|
|
321
|
+
class="relative flex w-full min-w-0 items-center px-2 py-1 wrap-break-word
|
|
203
322
|
{index % 2 ? 'bg-(--back-color)/40' : 'bg-[#edeef3] dark:bg-[#1f2a3a]'}
|
|
204
323
|
{column.align === 'center'
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
324
|
+
? 'flex justify-center text-center'
|
|
325
|
+
: column.align === 'right'
|
|
326
|
+
? 'flex justify-end text-right'
|
|
327
|
+
: 'flex justify-start text-left'}
|
|
209
328
|
border-t
|
|
210
329
|
{j !== 0 ? ' border-l ' : ''}
|
|
211
330
|
{outline ? 'border-(--border-color)' : 'border-transparent'} "
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
331
|
+
>
|
|
332
|
+
{#if column.buttons}
|
|
333
|
+
<div class="flex w-full flex-col gap-1">
|
|
334
|
+
{#each column.buttons as button (button)}
|
|
335
|
+
<button
|
|
336
|
+
class="{twMerge(`cursor-pointer rounded-full
|
|
218
337
|
px-4 py-1 font-semibold shadow-sm transition-shadow duration-200 outline-none select-none hover:shadow-md
|
|
219
338
|
${typeof button.class === 'function' ? button.class(row) : button.class}`)} bg-(--bg-color)"
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
339
|
+
onclick={() => buttonClick(row, button)}
|
|
340
|
+
>
|
|
341
|
+
{typeof button.name === 'function' ? button.name(row) : button.name}
|
|
342
|
+
</button>
|
|
343
|
+
{/each}
|
|
344
|
+
</div>
|
|
345
|
+
{:else if column.image?.src || column.image?.defaultIcon}
|
|
346
|
+
<div
|
|
347
|
+
class="flex items-center justify-center"
|
|
348
|
+
style={`width: ${column.image.width || '5rem'}; height: ${column.image.height || '5rem'};`}
|
|
349
|
+
>
|
|
350
|
+
{#if hasImage(column, row)}
|
|
351
|
+
<img
|
|
352
|
+
src={typeof column.image?.src === 'function' ? column.image.src(row) : column.image?.src || ''}
|
|
353
|
+
alt={column.image.alt ?? 'Image'}
|
|
354
|
+
class={twMerge(`h-full w-full object-cover ${column.image.class || ''}`)}
|
|
355
|
+
loading="lazy"
|
|
356
|
+
/>
|
|
357
|
+
{:else if column.image.defaultIcon}
|
|
358
|
+
{#if typeof column.image.defaultIcon === 'string'}
|
|
359
|
+
{@html column.image.defaultIcon}
|
|
360
|
+
{:else}
|
|
361
|
+
<column.image.defaultIcon />
|
|
362
|
+
{/if}
|
|
363
|
+
{/if}
|
|
364
|
+
</div>
|
|
365
|
+
{:else}
|
|
366
|
+
<div
|
|
367
|
+
class=" w-full max-w-full wrap-break-word {column.overflow?.truncated ? 'truncate' : ' whitespace-normal'}"
|
|
368
|
+
onmouseenter={column.overflow?.truncated ? (e) => showTooltip(e, row[column.key], column.overflow?.formatting) : undefined}
|
|
369
|
+
onmouseleave={column.overflow?.truncated ? hideTooltip : undefined}
|
|
370
|
+
onmousemove={column.overflow?.truncated
|
|
371
|
+
? (e) => {
|
|
372
|
+
tooltip.x = e.clientX
|
|
373
|
+
tooltip.y = e.clientY
|
|
374
|
+
}
|
|
375
|
+
: undefined}
|
|
376
|
+
role="columnheader"
|
|
377
|
+
tabindex={null}
|
|
378
|
+
>
|
|
379
|
+
{#if column.overflow?.modal}
|
|
380
|
+
<button
|
|
381
|
+
class="w-full cursor-pointer overflow-hidden text-left text-ellipsis whitespace-nowrap"
|
|
382
|
+
onclick={(e) => {
|
|
383
|
+
e.stopPropagation()
|
|
384
|
+
showModal(row[column.key], column.overflow?.formatting)
|
|
385
|
+
}}
|
|
386
|
+
>
|
|
387
|
+
{@html row[column.key]}
|
|
388
|
+
</button>
|
|
241
389
|
{:else}
|
|
242
|
-
|
|
390
|
+
{@html row[column.key]}
|
|
243
391
|
{/if}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
onmouseleave={column.overflow?.truncated ? hideTooltip : undefined}
|
|
251
|
-
onmousemove={column.overflow?.truncated
|
|
252
|
-
? (e) => {
|
|
253
|
-
tooltip.x = e.clientX
|
|
254
|
-
tooltip.y = e.clientY
|
|
255
|
-
}
|
|
256
|
-
: undefined}
|
|
257
|
-
role="columnheader"
|
|
258
|
-
tabindex={null}
|
|
259
|
-
>
|
|
260
|
-
{#if column.overflow?.modal}
|
|
392
|
+
</div>
|
|
393
|
+
<!-- {#if column.overflow?.truncated}
|
|
394
|
+
<div class="whitespace-nowrap">{row[column.key].slice(-5)}</div>
|
|
395
|
+
{/if} -->
|
|
396
|
+
|
|
397
|
+
{#if column.overflow?.copy}
|
|
261
398
|
<button
|
|
262
|
-
class="
|
|
399
|
+
class="mx-2 flex cursor-pointer border-none bg-transparent text-2xl"
|
|
263
400
|
onclick={(e) => {
|
|
264
|
-
e.
|
|
265
|
-
|
|
401
|
+
e.preventDefault()
|
|
402
|
+
navigator.clipboard.writeText(row[column.key])
|
|
403
|
+
copiedCell = { x: column.key as string, y: index }
|
|
404
|
+
setTimeout(() => (copiedCell = { x: '', y: -1 }), 1000)
|
|
266
405
|
}}
|
|
406
|
+
aria-label="Копировать текст"
|
|
267
407
|
>
|
|
268
|
-
|
|
408
|
+
<div class=" size-5 text-sm [&_svg]:h-full [&_svg]:max-h-full [&_svg]:w-full [&_svg]:max-w-full">
|
|
409
|
+
{#if copiedCell.y === index && copiedCell.x === column.key}
|
|
410
|
+
<div
|
|
411
|
+
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"
|
|
412
|
+
transition:fade={{ duration: 200 }}
|
|
413
|
+
>
|
|
414
|
+
✓
|
|
415
|
+
</div>
|
|
416
|
+
{:else}
|
|
417
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
|
|
418
|
+
<g fill="none" stroke="currentColor" stroke-width="1.5">
|
|
419
|
+
<path
|
|
420
|
+
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"
|
|
421
|
+
/>
|
|
422
|
+
<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" />
|
|
423
|
+
</g>
|
|
424
|
+
</svg>
|
|
425
|
+
{/if}
|
|
426
|
+
</div>
|
|
269
427
|
</button>
|
|
270
|
-
{:else}
|
|
271
|
-
{@html row[column.key]}
|
|
272
428
|
{/if}
|
|
273
|
-
</div>
|
|
274
|
-
<!-- {#if column.overflow?.truncated}
|
|
275
|
-
<div class="whitespace-nowrap">{row[column.key].slice(-5)}</div>
|
|
276
|
-
{/if} -->
|
|
277
|
-
|
|
278
|
-
{#if column.overflow?.copy}
|
|
279
|
-
<button
|
|
280
|
-
class="mx-2 flex cursor-pointer border-none bg-transparent text-2xl"
|
|
281
|
-
onclick={(e) => {
|
|
282
|
-
e.preventDefault()
|
|
283
|
-
navigator.clipboard.writeText(row[column.key])
|
|
284
|
-
copiedCell = { x: column.key as string, y: index }
|
|
285
|
-
setTimeout(() => (copiedCell = { x: '', y: -1 }), 1000)
|
|
286
|
-
}}
|
|
287
|
-
aria-label="Копировать текст"
|
|
288
|
-
>
|
|
289
|
-
<div class=" size-5 text-sm [&_svg]:h-full [&_svg]:max-h-full [&_svg]:w-full [&_svg]:max-w-full">
|
|
290
|
-
{#if copiedCell.y === index && copiedCell.x === column.key}
|
|
291
|
-
<div
|
|
292
|
-
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"
|
|
293
|
-
transition:fade={{ duration: 200 }}
|
|
294
|
-
>
|
|
295
|
-
✓
|
|
296
|
-
</div>
|
|
297
|
-
{:else}
|
|
298
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
|
|
299
|
-
<g fill="none" stroke="currentColor" stroke-width="1.5">
|
|
300
|
-
<path
|
|
301
|
-
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"
|
|
302
|
-
/>
|
|
303
|
-
<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" />
|
|
304
|
-
</g>
|
|
305
|
-
</svg>
|
|
306
|
-
{/if}
|
|
307
|
-
</div>
|
|
308
|
-
</button>
|
|
309
429
|
{/if}
|
|
310
|
-
|
|
311
|
-
|
|
430
|
+
</div>
|
|
431
|
+
{/each}
|
|
312
432
|
{/each}
|
|
313
|
-
|
|
433
|
+
</div>
|
|
314
434
|
</div>
|
|
315
|
-
|
|
435
|
+
{/if}
|
|
316
436
|
|
|
317
437
|
{#if tooltip.show}
|
|
318
438
|
<div
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { ITableProps } from '../types';
|
|
2
|
-
declare const Table: import("svelte").Component<ITableProps<any>, {}, "modalData">;
|
|
2
|
+
declare const Table: import("svelte").Component<ITableProps<any>, {}, "body" | "modalData">;
|
|
3
3
|
type Table = ReturnType<typeof Table>;
|
|
4
4
|
export default Table;
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
const DeviceVariables = getContext<{ id: string; value: string; name: string }[]>('DeviceVariables')
|
|
25
25
|
let VARIABLE_OPTIONS = $derived(DeviceVariables && Array.isArray(DeviceVariables) ? DeviceVariables : [])
|
|
26
26
|
|
|
27
|
-
let defaultIcon = $derived({ isModalOpen: false, columnIndex: 0, column: component.properties.header[0] })
|
|
27
|
+
let defaultIcon = $derived({ isModalOpen: false, columnIndex: 0, column: component.properties.header ? component.properties.header[0] : '' })
|
|
28
28
|
|
|
29
29
|
const initialColor = $derived(
|
|
30
30
|
$optionsStore.COLOR_OPTIONS.find((c) =>
|
|
@@ -95,6 +95,16 @@
|
|
|
95
95
|
value={$optionsStore.ACCESS_OPTION.find((o) => o.value === component.access)}
|
|
96
96
|
onUpdate={(option) => onPropertyChange({ access: option.value })}
|
|
97
97
|
/>
|
|
98
|
+
<UI.Select
|
|
99
|
+
label={{ name: $t('constructor.props.table.type') }}
|
|
100
|
+
type="buttons"
|
|
101
|
+
options={$optionsStore.TABLE_TYPE_OPTIONS}
|
|
102
|
+
value={$optionsStore.TABLE_TYPE_OPTIONS.find((o) => o.value === component.properties.type)}
|
|
103
|
+
onUpdate={(option) => {
|
|
104
|
+
updateProperty('type', option.value as string, component, onPropertyChange)
|
|
105
|
+
if (option.value === 'logger') updateProperty('stashData', true, component, onPropertyChange)
|
|
106
|
+
}}
|
|
107
|
+
/>
|
|
98
108
|
</div>
|
|
99
109
|
<div class="flex w-1/3 flex-col px-2">
|
|
100
110
|
<UI.Select
|
|
@@ -111,6 +121,14 @@
|
|
|
111
121
|
options={[{ id: crypto.randomUUID(), value: 0, class: '' }]}
|
|
112
122
|
onChange={(value) => updateProperty('outline', value, component, onPropertyChange)}
|
|
113
123
|
/>
|
|
124
|
+
<UI.Switch
|
|
125
|
+
label={{ name: $t('constructor.props.table.stashData') }}
|
|
126
|
+
value={component.properties.stashData}
|
|
127
|
+
options={[{ id: crypto.randomUUID(), value: 0, class: '', disabled: component.properties.type === 'logger' }]}
|
|
128
|
+
onChange={(value) => {
|
|
129
|
+
updateProperty('stashData', value, component, onPropertyChange)
|
|
130
|
+
}}
|
|
131
|
+
/>
|
|
114
132
|
</div>
|
|
115
133
|
<div class="flex w-1/3 flex-col px-2">
|
|
116
134
|
<UI.Input
|
|
@@ -125,6 +143,12 @@
|
|
|
125
143
|
options={$optionsStore.TEXT_ALIGN_OPTIONS}
|
|
126
144
|
onUpdate={(option) => updateProperty('label.class', twMerge(component.properties.label.class, option.value), component, onPropertyChange)}
|
|
127
145
|
/>
|
|
146
|
+
<UI.Input
|
|
147
|
+
label={{ name: $t('constructor.props.table.buffersize') }}
|
|
148
|
+
type="number"
|
|
149
|
+
value={component.properties.rowsAmmount}
|
|
150
|
+
onUpdate={(value) => updateProperty('rowsAmmount', value as string, component, onPropertyChange)}
|
|
151
|
+
/>
|
|
128
152
|
</div>
|
|
129
153
|
</div>
|
|
130
154
|
|
|
@@ -155,10 +179,9 @@
|
|
|
155
179
|
</div>
|
|
156
180
|
|
|
157
181
|
{#each component.properties.header as column, columnIndex (columnIndex)}
|
|
158
|
-
<div class="mr-2
|
|
182
|
+
<div class="mr-2 grid grid-cols-[minmax(5rem,10rem)_1fr_minmax(5rem,10rem)_minmax(10rem,21rem)_6rem_6rem_2rem_2rem] items-end gap-6">
|
|
159
183
|
<UI.Input
|
|
160
184
|
label={{ name: $t('constructor.props.table.columns.key') }}
|
|
161
|
-
wrapperClass="w-170"
|
|
162
185
|
value={column.key}
|
|
163
186
|
help={{ regExp: /^[0-9a-zA-Z_-]{0,16}$/ }}
|
|
164
187
|
onUpdate={(value) => {
|
|
@@ -175,7 +198,6 @@
|
|
|
175
198
|
/>
|
|
176
199
|
<UI.Input
|
|
177
200
|
label={{ name: $t('constructor.props.table.columns.width') }}
|
|
178
|
-
wrapperClass="w-150"
|
|
179
201
|
type="number"
|
|
180
202
|
value={Number(column.width.replace('%', ''))}
|
|
181
203
|
onUpdate={(value) => updateTableHeader(columnIndex, 'width', `${value}%`)}
|
|
@@ -188,14 +210,12 @@
|
|
|
188
210
|
onUpdate={(option) => updateTableHeader(columnIndex, 'align', option.value)}
|
|
189
211
|
/>
|
|
190
212
|
<UI.Switch
|
|
191
|
-
wrapperClass="w-30"
|
|
192
213
|
label={{ name: $t('constructor.props.table.columns.sortable'), class: 'px-0' }}
|
|
193
214
|
options={[{ id: crypto.randomUUID(), value: 0, class: '' }]}
|
|
194
215
|
value={column.sortable}
|
|
195
216
|
onChange={(value) => updateTableHeader(columnIndex, 'sortable', value)}
|
|
196
217
|
/>
|
|
197
218
|
<UI.Switch
|
|
198
|
-
wrapperClass="w-30"
|
|
199
219
|
label={{ name: $t('constructor.props.copy'), class: 'px-0' }}
|
|
200
220
|
options={[{ id: crypto.randomUUID(), value: 0, class: '' }]}
|
|
201
221
|
value={column.overflow?.copy}
|
|
@@ -314,6 +334,12 @@
|
|
|
314
334
|
updateProperty('options', options, component, onPropertyChange)
|
|
315
335
|
}}
|
|
316
336
|
/>
|
|
337
|
+
<UI.Switch
|
|
338
|
+
label={{ name: $t('constructor.props.outline') }}
|
|
339
|
+
value={component.properties.outline}
|
|
340
|
+
options={[{ id: crypto.randomUUID(), value: 0, class: '' }]}
|
|
341
|
+
onChange={(value) => updateProperty('outline', value, component, onPropertyChange)}
|
|
342
|
+
/>
|
|
317
343
|
</div>
|
|
318
344
|
<div class="flex w-1/3 flex-col px-2">
|
|
319
345
|
<UI.Select
|
|
@@ -333,19 +359,37 @@
|
|
|
333
359
|
value={component.properties.label.class}
|
|
334
360
|
onUpdate={(value) => updateProperty('label.class', value as string, component, onPropertyChange)}
|
|
335
361
|
/>
|
|
336
|
-
</div>
|
|
337
|
-
|
|
338
|
-
<div class="flex w-1/3 flex-col px-2">
|
|
339
362
|
<UI.Input
|
|
340
363
|
label={{ name: $t('constructor.props.footer') }}
|
|
341
364
|
value={component.properties.footer}
|
|
342
365
|
onUpdate={(value) => updateProperty('footer', value as string, component, onPropertyChange)}
|
|
343
366
|
/>
|
|
367
|
+
</div>
|
|
368
|
+
|
|
369
|
+
<div class="flex w-1/3 flex-col px-2">
|
|
370
|
+
<UI.Select
|
|
371
|
+
label={{ name: $t('constructor.props.table.type') }}
|
|
372
|
+
type="buttons"
|
|
373
|
+
options={$optionsStore.TABLE_TYPE_OPTIONS}
|
|
374
|
+
value={$optionsStore.TABLE_TYPE_OPTIONS.find((o) => o.value === component.properties.type)}
|
|
375
|
+
onUpdate={(option) => {
|
|
376
|
+
updateProperty('type', option.value as string, component, onPropertyChange)
|
|
377
|
+
if (option.value === 'logger') updateProperty('stashData', true, component, onPropertyChange)
|
|
378
|
+
}}
|
|
379
|
+
/>
|
|
344
380
|
<UI.Switch
|
|
345
|
-
label={{ name: $t('constructor.props.
|
|
346
|
-
value={component.properties.
|
|
347
|
-
options={[{ id: crypto.randomUUID(), value: 0, class: '' }]}
|
|
348
|
-
onChange={(value) =>
|
|
381
|
+
label={{ name: $t('constructor.props.table.stashData') }}
|
|
382
|
+
value={component.properties.stashData}
|
|
383
|
+
options={[{ id: crypto.randomUUID(), value: 0, class: '', disabled: component.properties.type === 'logger' }]}
|
|
384
|
+
onChange={(value) => {
|
|
385
|
+
updateProperty('stashData', value, component, onPropertyChange)
|
|
386
|
+
}}
|
|
387
|
+
/>
|
|
388
|
+
<UI.Input
|
|
389
|
+
label={{ name: $t('constructor.props.table.buffersize') }}
|
|
390
|
+
type="number"
|
|
391
|
+
value={component.properties.rowsAmmount}
|
|
392
|
+
onUpdate={(value) => updateProperty('rowsAmmount', value as string, component, onPropertyChange)}
|
|
349
393
|
/>
|
|
350
394
|
</div>
|
|
351
395
|
</div>
|
|
@@ -380,10 +424,9 @@
|
|
|
380
424
|
{#each component.properties.header as column, columnIndex (columnIndex)}
|
|
381
425
|
<div class="rounded-2xl border border-(--border-color) p-2">
|
|
382
426
|
<div class="mb-5">
|
|
383
|
-
<div class="mr-2
|
|
427
|
+
<div class="mr-2 grid grid-cols-[minmax(5rem,10rem)_1fr_minmax(5rem,10rem)_minmax(10rem,21rem)_6rem_6rem_2rem_2rem] items-end gap-6">
|
|
384
428
|
<UI.Input
|
|
385
429
|
label={{ name: $t('constructor.props.table.columns.key') }}
|
|
386
|
-
wrapperClass="w-150"
|
|
387
430
|
value={column.key}
|
|
388
431
|
help={{ regExp: /^[0-9a-zA-Z_-]{0,16}$/ }}
|
|
389
432
|
onUpdate={(value) => {
|
|
@@ -400,21 +443,25 @@
|
|
|
400
443
|
/>
|
|
401
444
|
<UI.Input
|
|
402
445
|
label={{ name: $t('constructor.props.table.columns.width'), class: 'px-0' }}
|
|
403
|
-
wrapperClass="w-150"
|
|
404
446
|
type="number"
|
|
405
447
|
value={Number(column.width.replace('%', ''))}
|
|
406
448
|
onUpdate={(value) => updateTableHeader(columnIndex, 'width', `${value}%`)}
|
|
407
449
|
/>
|
|
450
|
+
<UI.Select
|
|
451
|
+
label={{ name: $t('constructor.props.align.content') }}
|
|
452
|
+
type="buttons"
|
|
453
|
+
value={$optionsStore.ALIGN_OPTIONS.find((a) => (a.value as string).includes(column.align))}
|
|
454
|
+
options={$optionsStore.ALIGN_OPTIONS}
|
|
455
|
+
onUpdate={(option) => updateTableHeader(columnIndex, 'align', option.value)}
|
|
456
|
+
/>
|
|
408
457
|
<UI.Switch
|
|
409
458
|
label={{ name: $t('constructor.props.table.columns.sortable'), class: 'px-0' }}
|
|
410
|
-
wrapperClass="w-30"
|
|
411
459
|
options={[{ id: crypto.randomUUID(), value: 0, class: '' }]}
|
|
412
460
|
value={column.sortable}
|
|
413
461
|
onChange={(value) => updateTableHeader(columnIndex, 'sortable', value)}
|
|
414
462
|
/>
|
|
415
463
|
<UI.Switch
|
|
416
464
|
label={{ name: $t('constructor.props.copy'), class: 'px-0' }}
|
|
417
|
-
wrapperClass="w-30"
|
|
418
465
|
options={[{ id: crypto.randomUUID(), value: 0, class: '' }]}
|
|
419
466
|
value={column.overflow?.copy}
|
|
420
467
|
onChange={(value) => updateTableHeader(columnIndex, 'overflow', { copy: value, truncated: column.overflow?.truncated })}
|
|
@@ -446,22 +493,14 @@
|
|
|
446
493
|
}}
|
|
447
494
|
/>
|
|
448
495
|
</div>
|
|
449
|
-
<div class="mr-2
|
|
450
|
-
<UI.Select
|
|
451
|
-
label={{ name: $t('constructor.props.align.content') }}
|
|
452
|
-
type="buttons"
|
|
453
|
-
value={$optionsStore.ALIGN_OPTIONS.find((a) => (a.value as string).includes(column.align))}
|
|
454
|
-
options={$optionsStore.ALIGN_OPTIONS}
|
|
455
|
-
onUpdate={(option) => updateTableHeader(columnIndex, 'align', option.value)}
|
|
456
|
-
/>
|
|
496
|
+
<div class="mr-2 grid grid-cols-[5rem_minmax(8rem,16rem)_1fr_minmax(8rem,12rem)_minmax(8rem,12rem)] items-end justify-between gap-6">
|
|
457
497
|
<UI.Switch
|
|
458
|
-
|
|
459
|
-
label={{ name: $t('constructor.props.table.columns.truncated') }}
|
|
498
|
+
label={{ name: $t('constructor.props.table.columns.truncated'), class: 'px-0' }}
|
|
460
499
|
options={[{ id: crypto.randomUUID(), value: 0, class: '' }]}
|
|
461
500
|
value={column.overflow?.truncated}
|
|
462
501
|
onChange={(value) => updateTableHeader(columnIndex, 'overflow', { truncated: value, copy: column.overflow?.copy })}
|
|
463
502
|
/>
|
|
464
|
-
<div class="relative mt-6 flex w-full gap-2">
|
|
503
|
+
<div class="relative mt-6 flex items-center w-full gap-2">
|
|
465
504
|
<UI.Button
|
|
466
505
|
content={{ name: $t('constructor.props.table.columns.defaultIcon') }}
|
|
467
506
|
onClick={() => (defaultIcon = { isModalOpen: true, columnIndex: columnIndex, column: column })}
|
|
@@ -498,7 +537,6 @@
|
|
|
498
537
|
label={{ name: $t('constructor.props.table.columns.image.width'), class: 'px-0' }}
|
|
499
538
|
type="number"
|
|
500
539
|
number={{ minNum: 0, maxNum: 1000, step: 1 }}
|
|
501
|
-
wrapperClass="w-150"
|
|
502
540
|
value={Number(column.image?.width.replace('rem', '')) ?? 0}
|
|
503
541
|
onUpdate={(value) => {
|
|
504
542
|
updateTableHeader(columnIndex, 'image', {
|
|
@@ -513,7 +551,6 @@
|
|
|
513
551
|
label={{ name: $t('constructor.props.table.columns.image.height'), class: 'px-0' }}
|
|
514
552
|
type="number"
|
|
515
553
|
number={{ minNum: 0, maxNum: 1000, step: 1 }}
|
|
516
|
-
wrapperClass="w-150"
|
|
517
554
|
value={Number(column.image?.height.replace('rem', ''))}
|
|
518
555
|
onUpdate={(value) => {
|
|
519
556
|
updateTableHeader(columnIndex, 'image', {
|
|
@@ -132,6 +132,9 @@ const translations = {
|
|
|
132
132
|
'constructor.props.joystick.axes.info': 'Поле для ввода названий осей, разделенных пробелами (2 или 3 названия)',
|
|
133
133
|
'constructor.props.file.select': 'Выберите файл',
|
|
134
134
|
'constructor.props.file.notselected': 'Файл не выбран',
|
|
135
|
+
'constructor.props.table.type': 'Тип таблицы',
|
|
136
|
+
'constructor.props.table.type.table': 'Статическая таблица',
|
|
137
|
+
'constructor.props.table.type.logger': 'Таблица для логов',
|
|
135
138
|
'constructor.props.table.columns': 'Колонки таблицы',
|
|
136
139
|
'constructor.props.table.columns.key': 'Ключ',
|
|
137
140
|
'constructor.props.table.columns.label': 'Название колонки',
|
|
@@ -148,6 +151,8 @@ const translations = {
|
|
|
148
151
|
'constructor.props.table.addaction': 'Добавить кнопку',
|
|
149
152
|
'constructor.props.table.keys': 'Перечень ключей',
|
|
150
153
|
'constructor.props.table.keys.info': 'Ключи таблицы, значения которых будут возвращаться',
|
|
154
|
+
'constructor.props.table.stashData': 'Накопление данных',
|
|
155
|
+
'constructor.props.table.buffersize': 'Размер буфера',
|
|
151
156
|
'constructor.props.icon.access': 'Доступ',
|
|
152
157
|
'constructor.props.icon.common': 'Общее',
|
|
153
158
|
'constructor.props.icon.scenarios': 'Сценарии',
|
package/dist/options.d.ts
CHANGED
|
@@ -115,6 +115,11 @@ export declare const optionsStore: import("svelte/store").Readable<{
|
|
|
115
115
|
value: string;
|
|
116
116
|
name: string;
|
|
117
117
|
}[];
|
|
118
|
+
TABLE_TYPE_OPTIONS: {
|
|
119
|
+
id: string;
|
|
120
|
+
value: string;
|
|
121
|
+
name: string;
|
|
122
|
+
}[];
|
|
118
123
|
AUTOCOMPLETE_CONSTRUCTOR_OPTIONS: {
|
|
119
124
|
id: string;
|
|
120
125
|
value: string;
|
package/dist/options.js
CHANGED
|
@@ -124,6 +124,10 @@ export const optionsStore = derived(t, ($t) => {
|
|
|
124
124
|
{ id: id(), value: 'square', name: $t('constructor.props.type.square') },
|
|
125
125
|
{ id: id(), value: 'circle', name: $t('constructor.props.type.circle') },
|
|
126
126
|
],
|
|
127
|
+
TABLE_TYPE_OPTIONS: [
|
|
128
|
+
{ id: id(), value: 'table', name: $t('constructor.props.table.type.table') },
|
|
129
|
+
{ id: id(), value: 'logger', name: $t('constructor.props.table.type.logger') },
|
|
130
|
+
],
|
|
127
131
|
AUTOCOMPLETE_CONSTRUCTOR_OPTIONS: [
|
|
128
132
|
{ id: id(), value: 'on', name: $t('constructor.props.autocomplete.on') },
|
|
129
133
|
{ id: id(), value: 'off', name: $t('constructor.props.autocomplete.off') },
|
package/dist/types.d.ts
CHANGED
|
@@ -262,9 +262,12 @@ export interface ITableProps<T extends object> {
|
|
|
262
262
|
name?: string;
|
|
263
263
|
class?: string;
|
|
264
264
|
};
|
|
265
|
-
header
|
|
266
|
-
body: T[];
|
|
265
|
+
header?: ITableHeader<T>[];
|
|
266
|
+
body: T[] | T | null;
|
|
267
267
|
footer?: string;
|
|
268
|
+
type?: 'table' | 'logger';
|
|
269
|
+
stashData?: boolean;
|
|
270
|
+
rowsAmmount?: number;
|
|
268
271
|
outline?: boolean;
|
|
269
272
|
cursor?: string | null;
|
|
270
273
|
loader?: Writable<boolean>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "poe-svelte-ui-lib",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"build": "vite build",
|
|
9
9
|
"preview": "vite preview",
|
|
10
10
|
"prepack": "svelte-kit sync && svelte-package && publint",
|
|
11
|
-
"CheckUpdate": "npx npm-check-updates -u && npm install",
|
|
11
|
+
"CheckUpdate": "npx npm-check-updates -u && npm install && npm install prettier@3.6.2",
|
|
12
12
|
"UpdateIconsLib": "tsx src/lib/IconsCatalog/iconsLib.ts"
|
|
13
13
|
},
|
|
14
14
|
"svelte": "./dist/index.js",
|
|
@@ -49,9 +49,9 @@
|
|
|
49
49
|
"@sveltejs/vite-plugin-svelte": "^6.2.1",
|
|
50
50
|
"@types/node": "^24.10.1",
|
|
51
51
|
"publint": "^0.3.15",
|
|
52
|
-
"svelte": "^5.45.
|
|
52
|
+
"svelte": "^5.45.6",
|
|
53
53
|
"svelte-preprocess": "^6.0.3",
|
|
54
|
-
"vite": "^7.2.
|
|
54
|
+
"vite": "^7.2.7",
|
|
55
55
|
"vite-plugin-compression": "^0.5.1"
|
|
56
56
|
}
|
|
57
57
|
}
|