poe-svelte-ui-lib 1.18.0 → 1.19.0
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/Accordion/Accordion.svelte +5 -2
- package/dist/Button/Button.svelte +1 -13
- package/dist/FileAttach/FileAttach.svelte +15 -11
- package/dist/Input/Input.svelte +5 -2
- package/dist/Modal.svelte +1 -1
- package/dist/Select/Select.svelte +50 -3
- package/dist/Slider/Slider.svelte +13 -8
- package/dist/Table/Table.svelte +5 -1
- package/dist/Tabs/Tabs.svelte +57 -46
- package/dist/Widget/Widget.svelte +6 -6
- package/package.json +1 -1
|
@@ -20,8 +20,11 @@
|
|
|
20
20
|
|
|
21
21
|
<div id={`${id}-${crypto.randomUUID().slice(0, 6)}`} class={twMerge(`w-full`, wrapperClass)} transition:slide={{ duration: 200 }}>
|
|
22
22
|
<div class="overflow-hidden rounded-[14px] border border-(--hairline-color) bg-(--back-color)">
|
|
23
|
+
<!-- Заголовок темнее контента (--container-color), а не наоборот: так он читается
|
|
24
|
+
как отдельная кликабельная полоса, а раскрытое содержимое остаётся на чистом
|
|
25
|
+
светлом фоне (--back-color) — там часто лежат вложенные карточки/поля. -->
|
|
23
26
|
<button
|
|
24
|
-
class="flex w-full cursor-pointer items-center justify-between gap-3 px-4 py-3 text-left transition-colors duration-150 hover:bg-(--
|
|
27
|
+
class="flex w-full cursor-pointer items-center justify-between gap-3 bg-(--container-color) px-4 py-3 text-left transition-colors duration-150 hover:bg-(--border-color)"
|
|
25
28
|
onclick={toggle}
|
|
26
29
|
>
|
|
27
30
|
<div class="flex min-w-0 flex-1 items-center gap-3">
|
|
@@ -50,7 +53,7 @@
|
|
|
50
53
|
|
|
51
54
|
{#if isOpen}
|
|
52
55
|
<div
|
|
53
|
-
class="grid w-full gap-3 border-t border-(--hairline-color) bg-(--
|
|
56
|
+
class="grid w-full gap-3 border-t border-(--hairline-color) bg-(--back-color) p-4"
|
|
54
57
|
transition:slide={{ duration: 200 }}
|
|
55
58
|
style="grid-template-columns: repeat({size.width || 1}, minmax(0, 1fr));
|
|
56
59
|
grid-template-rows: repeat({size.height || 1}, {image ? 'minmax(6.5rem, auto)' : 'auto'});
|
|
@@ -70,18 +70,6 @@
|
|
|
70
70
|
}
|
|
71
71
|
})
|
|
72
72
|
|
|
73
|
-
const svgSize = $derived(() => {
|
|
74
|
-
const widthClass = twMerge(
|
|
75
|
-
wrapperClass.split(" ").find((cls: string) => cls.startsWith("w-")),
|
|
76
|
-
componentClass.split(" ").find((cls: string) => cls.startsWith("w-")),
|
|
77
|
-
)
|
|
78
|
-
const heightClass = twMerge(
|
|
79
|
-
wrapperClass.split(" ").find((cls: string) => cls.startsWith("h-")),
|
|
80
|
-
componentClass.split(" ").find((cls: string) => cls.startsWith("h-")),
|
|
81
|
-
)
|
|
82
|
-
return `${widthClass} ${heightClass}`
|
|
83
|
-
})
|
|
84
|
-
|
|
85
73
|
const handleClick = (event: Event) => {
|
|
86
74
|
if (disabled || !onClick) return
|
|
87
75
|
event?.stopPropagation()
|
|
@@ -134,7 +122,7 @@
|
|
|
134
122
|
{#if content?.icon}
|
|
135
123
|
<span
|
|
136
124
|
class={`flex shrink-0 items-center justify-center overflow-visible
|
|
137
|
-
${content.name?.trim() ? "h-[18px] w-[18px]" :
|
|
125
|
+
${content.name?.trim() ? "h-[18px] w-[18px]" : "h-full w-full"}
|
|
138
126
|
[&_svg]:h-full [&_svg]:max-h-full [&_svg]:w-full [&_svg]:max-w-full`}
|
|
139
127
|
>
|
|
140
128
|
{#if typeof content?.icon === "string"}
|
|
@@ -42,17 +42,21 @@
|
|
|
42
42
|
}
|
|
43
43
|
</script>
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
<!-- Не входил в исходный design-handoff (пропущен вместе с остальными точками,
|
|
46
|
+
которые авторы документа не осматривали) — сейчас приведён к общей палитре:
|
|
47
|
+
радиус 10/высота 36 как у Input/Select, сегмент "Выбрать файл" залит акцентом
|
|
48
|
+
с текстом --on-accent (было --font-color по тёмно-синему — нечитаемо). -->
|
|
49
|
+
<div class={twMerge(`flex flex-col items-center gap-1`, wrapperClass)}>
|
|
46
50
|
{#if label.name}
|
|
47
|
-
<
|
|
51
|
+
<span class={twMerge(`w-full text-[12px] font-semibold text-(--muted-color)`, label.class)}>{label.name}</span>
|
|
48
52
|
{/if}
|
|
49
53
|
|
|
50
54
|
{#if type === "image"}
|
|
51
55
|
<div class="relative">
|
|
52
56
|
<button
|
|
53
|
-
class="flex items-center justify-center overflow-hidden {imageSize.form === 'circle' ? 'rounded-full' : 'rounded-2xl'}
|
|
54
|
-
|
|
55
|
-
{disabled ? 'cursor-not-allowed opacity-
|
|
57
|
+
class="flex items-center justify-center overflow-hidden {imageSize.form === 'circle' ? 'rounded-full' : 'rounded-2xl'}
|
|
58
|
+
border border-(--hairline-color) bg-(--container-color) transition-colors duration-150
|
|
59
|
+
{disabled ? 'cursor-not-allowed opacity-45' : 'cursor-pointer hover:bg-(--border-color)'}"
|
|
56
60
|
style={`height: ${imageSize.height}; width: ${imageSize.width}`}
|
|
57
61
|
onclick={triggerFileInput}
|
|
58
62
|
{disabled}
|
|
@@ -67,7 +71,7 @@
|
|
|
67
71
|
`}
|
|
68
72
|
/>
|
|
69
73
|
{:else}
|
|
70
|
-
<span class="text-
|
|
74
|
+
<span class="text-[12px] font-medium text-(--faint-color)">Image</span>
|
|
71
75
|
{/if}
|
|
72
76
|
</button>
|
|
73
77
|
<input id={ID} type="file" class="absolute -z-10 h-0 w-0 overflow-hidden opacity-0" {accept} {disabled} onchange={handleFileChange} />
|
|
@@ -77,19 +81,19 @@
|
|
|
77
81
|
<input
|
|
78
82
|
id={ID}
|
|
79
83
|
type="file"
|
|
80
|
-
class="absolute left-0 z-1 h-
|
|
84
|
+
class="absolute left-0 z-1 h-9 w-full opacity-0 {disabled ? 'cursor-not-allowed' : 'cursor-pointer'}"
|
|
81
85
|
{accept}
|
|
82
86
|
{disabled}
|
|
83
87
|
onchange={handleFileChange}
|
|
84
88
|
/>
|
|
85
89
|
<div
|
|
86
|
-
class="flex w-full overflow-hidden rounded-
|
|
87
|
-
"
|
|
90
|
+
class="flex h-9 w-full overflow-hidden rounded-[10px] border border-(--border-color) text-[14px] transition-colors duration-150
|
|
91
|
+
{disabled ? 'opacity-45' : 'hover:border-(--faint-color)'}"
|
|
88
92
|
>
|
|
89
|
-
<div class="flex
|
|
93
|
+
<div class="flex shrink-0 items-center justify-center bg-(--accent-color) px-3 font-semibold whitespace-nowrap text-(--on-accent)">
|
|
90
94
|
{$T("constructor.props.file.select")}
|
|
91
95
|
</div>
|
|
92
|
-
<div class="flex flex-1 items-center justify-start truncate bg-(--
|
|
96
|
+
<div class="flex min-w-0 flex-1 items-center justify-start truncate bg-(--field-color) px-3 text-(--font-color)">
|
|
93
97
|
<p class="truncate">{fileName || $T("constructor.props.file.notselected")}</p>
|
|
94
98
|
</div>
|
|
95
99
|
</div>
|
package/dist/Input/Input.svelte
CHANGED
|
@@ -239,7 +239,10 @@
|
|
|
239
239
|
{/if}
|
|
240
240
|
</div>
|
|
241
241
|
|
|
242
|
-
{#if
|
|
243
|
-
|
|
242
|
+
{#if help.regExp}
|
|
243
|
+
<!-- Место под ошибку зарезервировано всегда (высота фиксирована), чтобы её появление
|
|
244
|
+
не двигало соседние элементы — кнопку в одной строке с полем (как в восстановлении
|
|
245
|
+
пароля) или соседние поля формы. -->
|
|
246
|
+
<span class="block h-4 text-[12px] text-(--red-color)">{!isValid ? "Неверный формат" : ""}</span>
|
|
244
247
|
{/if}
|
|
245
248
|
</div>
|
package/dist/Modal.svelte
CHANGED
|
@@ -97,7 +97,7 @@
|
|
|
97
97
|
</button>
|
|
98
98
|
</div>
|
|
99
99
|
|
|
100
|
-
<div class={twMerge("flex h-full w-full flex-col overflow-auto p-5", mainClass)}>
|
|
100
|
+
<div class={twMerge("flex h-full w-full min-h-0 flex-col overflow-x-hidden overflow-y-auto p-5", mainClass)}>
|
|
101
101
|
{@render main?.()}
|
|
102
102
|
</div>
|
|
103
103
|
|
|
@@ -10,6 +10,38 @@
|
|
|
10
10
|
|
|
11
11
|
let isDropdownOpen = $state(false)
|
|
12
12
|
let dropdownElement: HTMLDivElement
|
|
13
|
+
let portalElement: HTMLDivElement | undefined = $state()
|
|
14
|
+
let anchorRect: { top: number; bottom: number; left: number; width: number } | null = $state(null)
|
|
15
|
+
|
|
16
|
+
/* Список вариантов выносится в document.body (портал), чтобы его не обрезал
|
|
17
|
+
overflow-hidden/overflow-auto ближайшего скроллящегося предка (например,
|
|
18
|
+
панель свойств конструктора). Позиция считается от dropdownElement и
|
|
19
|
+
обновляется, пока список открыт, при скролле/резайзе где угодно на странице. */
|
|
20
|
+
function portal(node: HTMLElement) {
|
|
21
|
+
document.body.appendChild(node)
|
|
22
|
+
return {
|
|
23
|
+
destroy() {
|
|
24
|
+
node.remove()
|
|
25
|
+
},
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function updateAnchorRect() {
|
|
30
|
+
if (!dropdownElement) return
|
|
31
|
+
const rect = dropdownElement.getBoundingClientRect()
|
|
32
|
+
anchorRect = { top: rect.top, bottom: rect.bottom, left: rect.left, width: rect.width }
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
$effect(() => {
|
|
36
|
+
if (!isDropdownOpen) return
|
|
37
|
+
updateAnchorRect()
|
|
38
|
+
window.addEventListener("scroll", updateAnchorRect, true)
|
|
39
|
+
window.addEventListener("resize", updateAnchorRect)
|
|
40
|
+
return () => {
|
|
41
|
+
window.removeEventListener("scroll", updateAnchorRect, true)
|
|
42
|
+
window.removeEventListener("resize", updateAnchorRect)
|
|
43
|
+
}
|
|
44
|
+
})
|
|
13
45
|
|
|
14
46
|
let {
|
|
15
47
|
id = crypto.randomUUID(),
|
|
@@ -41,7 +73,10 @@
|
|
|
41
73
|
)
|
|
42
74
|
|
|
43
75
|
const handleClickOutside = (event: MouseEvent) => {
|
|
44
|
-
|
|
76
|
+
const target = event.target as Node
|
|
77
|
+
const insideAnchor = !!dropdownElement?.contains(target)
|
|
78
|
+
const insidePortal = !!portalElement?.contains(target)
|
|
79
|
+
if (!insideAnchor && !insidePortal) isDropdownOpen = false
|
|
45
80
|
}
|
|
46
81
|
|
|
47
82
|
onMount(() => {
|
|
@@ -135,7 +170,13 @@
|
|
|
135
170
|
</button>
|
|
136
171
|
|
|
137
172
|
{#if isDropdownOpen}
|
|
138
|
-
<div
|
|
173
|
+
<div
|
|
174
|
+
use:portal
|
|
175
|
+
bind:this={portalElement}
|
|
176
|
+
class="fixed z-[9999] mt-1"
|
|
177
|
+
style="top: {anchorRect?.bottom ?? 0}px; left: {anchorRect?.left ?? 0}px; width: {anchorRect?.width ?? 0}px;"
|
|
178
|
+
transition:slide={{ duration: 150 }}
|
|
179
|
+
>
|
|
139
180
|
<div class={listBase} style="max-height: {listHeight};" role="listbox">
|
|
140
181
|
{#each options as option (option.id)}
|
|
141
182
|
<button
|
|
@@ -214,7 +255,13 @@
|
|
|
214
255
|
/>
|
|
215
256
|
|
|
216
257
|
{#if isDropdownOpen}
|
|
217
|
-
<div
|
|
258
|
+
<div
|
|
259
|
+
use:portal
|
|
260
|
+
bind:this={portalElement}
|
|
261
|
+
class="fixed z-[9999] mt-1 select-none"
|
|
262
|
+
style="top: {anchorRect?.bottom ?? 0}px; left: {anchorRect?.left ?? 0}px; width: {anchorRect?.width ?? 0}px;"
|
|
263
|
+
transition:slide={{ duration: 150 }}
|
|
264
|
+
>
|
|
218
265
|
<div class={listBase} style="max-height: {listHeight};" role="listbox">
|
|
219
266
|
{#each filteredOptions as option (option.id)}
|
|
220
267
|
<button
|
|
@@ -92,16 +92,19 @@
|
|
|
92
92
|
подбирать под конкретную высоту трека, и он даёт разный результат в Chromium и
|
|
93
93
|
Safari/WebKit — при равных высотах input и thumb смещения нет по определению,
|
|
94
94
|
это работает одинаково везде. */
|
|
95
|
+
/* Бегунок: было border-(--hairline-color) (почти прозрачная линия) + мягкая тень —
|
|
96
|
+
на светлом фоне белый кружок буквально сливался с дорожкой. Рамка в 2px цветом
|
|
97
|
+
заливки даёт чёткий, "премиальный" контур вместо почти невидимой линии. */
|
|
95
98
|
const THUMB = `w-full appearance-none bg-transparent h-[18px]
|
|
96
99
|
[&::-webkit-slider-runnable-track]:h-[18px] [&::-webkit-slider-runnable-track]:bg-transparent
|
|
97
100
|
[&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:size-[18px]
|
|
98
101
|
[&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-white
|
|
99
|
-
[&::-webkit-slider-thumb]:border [&::-webkit-slider-thumb]:border-(--
|
|
100
|
-
[&::-webkit-slider-thumb]:shadow-[
|
|
102
|
+
[&::-webkit-slider-thumb]:border-2 [&::-webkit-slider-thumb]:border-(--bg-color,var(--accent-color))
|
|
103
|
+
[&::-webkit-slider-thumb]:shadow-[0_1px_4px_rgb(16_24_40/0.35)]
|
|
101
104
|
[&::-moz-range-track]:h-[18px] [&::-moz-range-track]:bg-transparent [&::-moz-range-track]:border-0
|
|
102
105
|
[&::-moz-range-thumb]:size-[18px] [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:bg-white
|
|
103
|
-
[&::-moz-range-thumb]:border [&::-moz-range-thumb]:border-(--
|
|
104
|
-
[&::-moz-range-thumb]:shadow-[
|
|
106
|
+
[&::-moz-range-thumb]:border-2 [&::-moz-range-thumb]:border-(--bg-color,var(--accent-color))
|
|
107
|
+
[&::-moz-range-thumb]:shadow-[0_1px_4px_rgb(16_24_40/0.35)]
|
|
105
108
|
focus-visible:outline-none`
|
|
106
109
|
|
|
107
110
|
/* Двойной слайдер: оба input на всю ширину трека с ОДИНАКОВЫМ min/max,
|
|
@@ -123,17 +126,19 @@
|
|
|
123
126
|
id={`${id}-${crypto.randomUUID().slice(0, 6)}`}
|
|
124
127
|
class="relative flex h-8 flex-1 items-center {disabled ? 'cursor-not-allowed opacity-45' : ''}"
|
|
125
128
|
>
|
|
126
|
-
<!-- Фон дорожки
|
|
127
|
-
|
|
129
|
+
<!-- Фон дорожки 6px — --container-color здесь давал слишком слабый контраст
|
|
130
|
+
с фоном страницы (#f0f2f5 на белом), дорожка визуально пропадала;
|
|
131
|
+
--border-color заметно контрастнее и совпадает с рамкой счётчика ниже. -->
|
|
132
|
+
<div class="pointer-events-none absolute inset-x-0 top-1/2 h-1.5 -translate-y-1/2 rounded-full bg-(--border-color)"></div>
|
|
128
133
|
<!-- Заливка -->
|
|
129
134
|
{#if isRange}
|
|
130
135
|
<div
|
|
131
|
-
class="pointer-events-none absolute top-1/2 h-1 -translate-y-1/2 rounded-full bg-(--bg-color,var(--accent-color))"
|
|
136
|
+
class="pointer-events-none absolute top-1/2 h-1.5 -translate-y-1/2 rounded-full bg-(--bg-color,var(--accent-color))"
|
|
132
137
|
style="left: {pct(lowerValue)}%; width: {Math.max(0, pct(upperValue) - pct(lowerValue))}%;"
|
|
133
138
|
></div>
|
|
134
139
|
{:else}
|
|
135
140
|
<div
|
|
136
|
-
class="pointer-events-none absolute top-1/2 left-0 h-1 -translate-y-1/2 rounded-full bg-(--bg-color,var(--accent-color))"
|
|
141
|
+
class="pointer-events-none absolute top-1/2 left-0 h-1.5 -translate-y-1/2 rounded-full bg-(--bg-color,var(--accent-color))"
|
|
137
142
|
style="width: {pct(singleValue)}%;"
|
|
138
143
|
></div>
|
|
139
144
|
{/if}
|
package/dist/Table/Table.svelte
CHANGED
|
@@ -314,7 +314,11 @@
|
|
|
314
314
|
<div
|
|
315
315
|
id="rowDiv{i}-{j}"
|
|
316
316
|
class="relative grid min-h-7 w-full min-w-0 items-center gap-x-2 px-3 py-1 text-[13px] wrap-break-word
|
|
317
|
-
{column.align === 'center'
|
|
317
|
+
{column.align === 'center'
|
|
318
|
+
? 'justify-center justify-items-center text-center'
|
|
319
|
+
: column.align === 'right'
|
|
320
|
+
? 'justify-end justify-items-end text-right tabular-nums'
|
|
321
|
+
: 'justify-start justify-items-start text-left'}
|
|
318
322
|
{j !== 0 ? ' border-l ' : ''} {outline ? 'border-(--hairline-color)' : 'border-transparent'} {column.disableSelect ? 'select-none' : 'select-all'}"
|
|
319
323
|
style=" grid-template-columns: repeat({contentArray?.length}, minmax(0, 1fr));"
|
|
320
324
|
>
|
package/dist/Tabs/Tabs.svelte
CHANGED
|
@@ -30,55 +30,66 @@
|
|
|
30
30
|
|
|
31
31
|
<div id={`${id}-${crypto.randomUUID().slice(0, 6)}`} class="h-full w-full">
|
|
32
32
|
<div class="flex h-full w-full flex-col overflow-hidden rounded-[14px] border border-(--hairline-color) bg-(--back-color)">
|
|
33
|
-
<!-- Полоса вкладок
|
|
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
|
-
|
|
33
|
+
<!-- Полоса вкладок — outer оставлен «чистым» скролл-контейнером без justify-*:
|
|
34
|
+
justify-content на самом overflow-x-auto блоке при контенте чуть шире контейнера
|
|
35
|
+
даёт паразитный горизонтальный скролл на пару px даже когда прокручивать нечего
|
|
36
|
+
(классический баг центрирования flex-контейнера с overflow). Поэтому justify-*
|
|
37
|
+
из wrapperClass уходит на внутреннюю обёртку, а не на сам скролл-контейнер. -->
|
|
38
|
+
<div class="sticky top-0 z-40 flex h-fit items-center overflow-x-auto border-b border-(--hairline-color) px-4">
|
|
39
|
+
<div class={twMerge(`flex w-full items-center gap-6`, wrapperClass)}>
|
|
40
|
+
{#each items as item, index}
|
|
41
|
+
<button
|
|
42
|
+
class={twMerge(
|
|
43
|
+
`tab relative flex min-w-fit shrink-0 items-center justify-center gap-2 border-0 bg-transparent py-3 text-[14px]
|
|
44
|
+
transition-colors duration-150 ${isCol && items.find((item) => item.icon) ? "h-20 flex-col" : ""}
|
|
45
|
+
${
|
|
46
|
+
index === currentTabIndex
|
|
47
|
+
? "cursor-pointer font-semibold text-(--font-color) shadow-[inset_0_-2px_0_var(--accent-color)]"
|
|
48
|
+
: item.disabled
|
|
49
|
+
? "cursor-not-allowed font-medium text-(--faint-color)"
|
|
50
|
+
: "cursor-pointer font-medium text-(--muted-color) hover:text-(--font-color)"
|
|
51
|
+
}`,
|
|
52
|
+
item.class,
|
|
53
|
+
)}
|
|
54
|
+
disabled={item.disabled}
|
|
55
|
+
style="width: {item.class
|
|
56
|
+
?.split(' ')
|
|
57
|
+
.find((cls: string) => cls.startsWith('w-'))
|
|
58
|
+
?.replace('w-[', '')
|
|
59
|
+
.slice(0, -1)};"
|
|
60
|
+
onclick={() => {
|
|
61
|
+
currentTabIndex = index
|
|
62
|
+
if (item.onClick) item.onClick()
|
|
63
|
+
}}
|
|
64
|
+
aria-selected={index === currentTabIndex}
|
|
65
|
+
role="tab"
|
|
66
|
+
>
|
|
67
|
+
{#if item?.icon}
|
|
68
|
+
<span class="flex size-[18px] items-center justify-center overflow-visible [&_svg]:h-full [&_svg]:w-full">
|
|
69
|
+
{#if typeof item.icon === "string"}
|
|
70
|
+
{@html item.icon}
|
|
71
|
+
{:else}
|
|
72
|
+
{@const IconComponent = item.icon}
|
|
73
|
+
<IconComponent />
|
|
74
|
+
{/if}
|
|
75
|
+
</span>
|
|
76
|
+
{/if}
|
|
77
|
+
{#if item?.name}
|
|
78
|
+
<span class="whitespace-nowrap">{item.name}</span>
|
|
79
|
+
{/if}
|
|
80
|
+
</button>
|
|
81
|
+
{/each}
|
|
82
|
+
</div>
|
|
77
83
|
</div>
|
|
78
84
|
|
|
79
|
-
<!-- Контент вкладки
|
|
85
|
+
<!-- Контент вкладки — overflow-x-hidden явно рядом с overflow-y-auto: у некоторых
|
|
86
|
+
потребителей (например, кнопка отправки формы логина в DevCloud) есть элемент
|
|
87
|
+
с col-start-2 при единственной явной колонке — он намеренно живёт в неявно
|
|
88
|
+
создаваемой второй колонке грида. Без overflow-x-hidden спека CSS трактует это
|
|
89
|
+
как реальное горизонтальное переполнение (раз overflow-y уже не visible, ось X
|
|
90
|
+
тоже становится auto) и рисует паразитный горизонтальный скролл на пару px. -->
|
|
80
91
|
<div
|
|
81
|
-
class="grid w-full flex-1 gap-3 overflow-y-auto bg-(--back-color) p-4"
|
|
92
|
+
class="grid w-full min-h-0 flex-1 gap-3 overflow-x-hidden overflow-y-auto bg-(--back-color) p-4"
|
|
82
93
|
style="grid-template-columns: repeat({size.width || 1}, minmax(0, 1fr)); grid-template-rows: repeat({size.height || 1}, auto);"
|
|
83
94
|
>
|
|
84
95
|
{#if Components}
|
|
@@ -116,12 +116,12 @@
|
|
|
116
116
|
[&::-webkit-slider-runnable-track]:h-8 [&::-webkit-slider-runnable-track]:bg-transparent
|
|
117
117
|
[&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:size-[18px] [&::-webkit-slider-thumb]:mt-[7px]
|
|
118
118
|
[&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-white
|
|
119
|
-
[&::-webkit-slider-thumb]:border [&::-webkit-slider-thumb]:border-(--
|
|
120
|
-
[&::-webkit-slider-thumb]:shadow-[
|
|
119
|
+
[&::-webkit-slider-thumb]:border-2 [&::-webkit-slider-thumb]:border-(--bg-color,var(--accent-color))
|
|
120
|
+
[&::-webkit-slider-thumb]:shadow-[0_1px_4px_rgb(16_24_40/0.35)]
|
|
121
121
|
[&::-moz-range-track]:h-8 [&::-moz-range-track]:bg-transparent [&::-moz-range-track]:border-0
|
|
122
122
|
[&::-moz-range-thumb]:size-[18px] [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:bg-white
|
|
123
|
-
[&::-moz-range-thumb]:border [&::-moz-range-thumb]:border-(--
|
|
124
|
-
[&::-moz-range-thumb]:shadow-[
|
|
123
|
+
[&::-moz-range-thumb]:border-2 [&::-moz-range-thumb]:border-(--bg-color,var(--accent-color))
|
|
124
|
+
[&::-moz-range-thumb]:shadow-[0_1px_4px_rgb(16_24_40/0.35)]
|
|
125
125
|
focus-visible:outline-none`
|
|
126
126
|
</script>
|
|
127
127
|
|
|
@@ -272,9 +272,9 @@
|
|
|
272
272
|
>
|
|
273
273
|
|
|
274
274
|
<div class="relative flex h-8 min-w-0 flex-1 items-center">
|
|
275
|
-
<div class="pointer-events-none absolute inset-x-0 top-1/2 h-1 -translate-y-1/2 rounded-full bg-(--back-color)"></div>
|
|
275
|
+
<div class="pointer-events-none absolute inset-x-0 top-1/2 h-1.5 -translate-y-1/2 rounded-full bg-(--back-color)"></div>
|
|
276
276
|
<div
|
|
277
|
-
class="pointer-events-none absolute top-1/2 left-0 h-1 -translate-y-1/2 rounded-full bg-(--bg-color,var(--accent-color))"
|
|
277
|
+
class="pointer-events-none absolute top-1/2 left-0 h-1.5 -translate-y-1/2 rounded-full bg-(--bg-color,var(--accent-color))"
|
|
278
278
|
style="width: {pct()}%;"
|
|
279
279
|
></div>
|
|
280
280
|
<input
|