poe-svelte-ui-lib 1.59.0 → 1.61.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/README.md +2 -0
- package/dist/Select/README.md +16 -15
- package/dist/Select/Select.svelte +7 -3
- package/dist/WidgetHeader.svelte +47 -32
- package/dist/WidgetStackInfo/WidgetStackInfo.svelte +1 -1
- package/dist/types.d.ts +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -59,6 +59,8 @@ npm install poe-svelte-ui-lib
|
|
|
59
59
|
|
|
60
60
|
**Названия смарт-виджетов** — в словаре библиотеки на всех языках (WiFi, «Об устройстве», «Файловая система», «Стек и задачи», «RGB лента», «Пилотажный дисплей», «Карта»); пустой `label.name` показывает название на языке пользователя, `widgetTitle(type)` отдаёт его сразу на всех языках `{ ru, en, zh }` — так конструктор заполняет заголовок нового виджета.
|
|
61
61
|
|
|
62
|
+
**Шапка смарт-виджета** (`WidgetHeader`): значок, заголовок и сворачивание слева, «?» в правом краю; правая часть (режимы, «Обновить» и т. п.) стоит в той же строке, а если не помещается — уходит второй строкой под заголовок и там переносится.
|
|
63
|
+
|
|
62
64
|
**Подсказки смарт-виджетов** — `hints.ts`: у каждого виджета своя кнопка «?» в правом краю шапки (`WidgetHeader` с пропом `hints`), по умолчанию подсказки выключены, выбор оператора запоминается в браузере для виджетов этого типа (`hintsSetting("WidgetPFD")`, ключ `localStorage` `WidgetHints.<тип>`, пишется только по нажатию «?»), глобального переключателя нет. Элемент получает подсказку действием `use:hint={{ text, enabled: $hints }}` — всплывающее окно в стиле темы над элементом; тексты — в словаре библиотеки (`widget.*.hint.*`), только там, где смысл поля не очевиден.
|
|
63
65
|
|
|
64
66
|
**Предпросмотр темы** — вкладка «Тема» на главной витрины (`src/routes/ThemePreview.svelte`): палитра токенов и состояния, затем все компоненты и виджеты в порядке меню витрины — каждый тип в своём разделе с живыми демо-данными (графики, видео, полёт для PFD и карты), в конце типографика и Markdown; тема переключается кнопкой в шапке витрины. Правьте `theme.css` и смотрите результат там.
|
package/dist/Select/README.md
CHANGED
|
@@ -37,21 +37,22 @@
|
|
|
37
37
|
|
|
38
38
|
## Пропсы
|
|
39
39
|
|
|
40
|
-
| Название | Тип | По умолчанию | Описание
|
|
41
|
-
| ---------------- | --------------------------------------------- | --------------------- |
|
|
42
|
-
| `id` | `string` | `crypto.randomUUID()` | Уникальный идентификатор компонента
|
|
43
|
-
| `wrapperClass` | `string` | `""` | Дополнительные CSS-классы для обертки компонента
|
|
44
|
-
| `componentClass` | `string` | `""` | Дополнительные CSS-классы для самого поля/кнопок выбора
|
|
45
|
-
| `disabled` | `boolean` | `false` | Состояние отключения компонента
|
|
46
|
-
| `label` | `object` | `-` | Настройки заголовка компонента
|
|
47
|
-
| `label.name` | `string` | `""` | Текст заголовка компонента
|
|
48
|
-
| `label.class` | `string` | `""` | CSS-классы для стилизации текста заголовка
|
|
49
|
-
| `type` | `"select" \| "buttons" \| "input"` | `"select"` | Тип отображения: `select` — выпадающий список с кнопкой, `buttons` — горизонтальный ряд кнопок, `input` — поле ввода с автодополнением и поиском
|
|
50
|
-
| `multiSelect` | `boolean` | `false` | Режим множественного выбора: работает только с `type: "buttons"`; при `true` позволяет выбирать несколько опций, значение передаётся как массив
|
|
51
|
-
| `
|
|
52
|
-
| `
|
|
53
|
-
| `
|
|
54
|
-
| `
|
|
40
|
+
| Название | Тип | По умолчанию | Описание |
|
|
41
|
+
| ---------------- | --------------------------------------------- | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
42
|
+
| `id` | `string` | `crypto.randomUUID()` | Уникальный идентификатор компонента |
|
|
43
|
+
| `wrapperClass` | `string` | `""` | Дополнительные CSS-классы для обертки компонента |
|
|
44
|
+
| `componentClass` | `string` | `""` | Дополнительные CSS-классы для самого поля/кнопок выбора |
|
|
45
|
+
| `disabled` | `boolean` | `false` | Состояние отключения компонента |
|
|
46
|
+
| `label` | `object` | `-` | Настройки заголовка компонента |
|
|
47
|
+
| `label.name` | `string` | `""` | Текст заголовка компонента |
|
|
48
|
+
| `label.class` | `string` | `""` | CSS-классы для стилизации текста заголовка |
|
|
49
|
+
| `type` | `"select" \| "buttons" \| "input"` | `"select"` | Тип отображения: `select` — выпадающий список с кнопкой, `buttons` — горизонтальный ряд кнопок, `input` — поле ввода с автодополнением и поиском |
|
|
50
|
+
| `multiSelect` | `boolean` | `false` | Режим множественного выбора: работает только с `type: "buttons"`; при `true` позволяет выбирать несколько опций, значение передаётся как массив |
|
|
51
|
+
| `fitContent` | `boolean` | `false` | Для `type="buttons"`: группа по ширине содержимого — все кнопки одинаковой ширины по самой длинной подписи, текст без переноса и обрезки (шапки, переключатели режимов) |
|
|
52
|
+
| `listHeight` | `string` | `"16rem"` | Максимальная высота выпадающего списка опций (для типов `select`/`input`) |
|
|
53
|
+
| `value` | `IOption<T> \| IOption<T>[] \| undefined` | `undefined` | Текущее выбранное значение(я); поддерживает двустороннее связывание (`$bindable`) |
|
|
54
|
+
| `options` | `IOption<T>[]` | `[]` | Массив доступных опций |
|
|
55
|
+
| `onUpdate` | `(value: IOption<T> \| IOption<T>[]) => void` | `undefined` | Обработчик изменения значения |
|
|
55
56
|
|
|
56
57
|
> **`bitMode`/`range`**: эти поля объявлены в типе `ISelectProps` и настраиваются в конструкторской панели (`SelectProps.svelte`), но сам `Select.svelte` их не читает и не использует — они не оказывают никакого эффекта на голый `<UI.Select>`. Если нужен битовый выбор в реальном рантайме, интерпретируйте маску на стороне вызывающего кода и передавайте уже готовый `value`/`options`.
|
|
57
58
|
|
|
@@ -55,6 +55,7 @@
|
|
|
55
55
|
disabled = false,
|
|
56
56
|
label = { name: "", class: "" },
|
|
57
57
|
multiSelect = false,
|
|
58
|
+
fitContent = false,
|
|
58
59
|
listHeight = "16rem",
|
|
59
60
|
type = "select",
|
|
60
61
|
value = $bindable(),
|
|
@@ -206,7 +207,9 @@
|
|
|
206
207
|
<!-- Сплошная группа: общий контур, разделители внутри, без зазоров и теней -->
|
|
207
208
|
<div
|
|
208
209
|
id={`${id}-${crypto.randomUUID().slice(0, 6)}`}
|
|
209
|
-
class="flex w-full rounded-[10px] border border-(--border-color) {disabled
|
|
210
|
+
class="{fitContent ? 'grid w-max auto-cols-fr grid-flow-col' : 'flex w-full'} rounded-[10px] border border-(--border-color) {disabled
|
|
211
|
+
? 'opacity-45'
|
|
212
|
+
: ''}"
|
|
210
213
|
role="group"
|
|
211
214
|
>
|
|
212
215
|
{#each options as option, index (option.id)}
|
|
@@ -221,7 +224,7 @@
|
|
|
221
224
|
для обычного сегмент-контрола без своего цвета (Access, Header и т.п.) поведение
|
|
222
225
|
прежнее — акцентная заливка только у выбранного пункта. -->
|
|
223
226
|
<!-- Обёртка — позиционирующий предок подсказки; overflow-hidden у группы убран, иначе подсказка обрезается -->
|
|
224
|
-
<div class="relative flex min-w-0 flex-1">
|
|
227
|
+
<div class="relative flex {fitContent ? '' : 'min-w-0 flex-1'}">
|
|
225
228
|
<button
|
|
226
229
|
id={option.id}
|
|
227
230
|
class="{twMerge(
|
|
@@ -237,7 +240,8 @@
|
|
|
237
240
|
? 'text-(--on-accent)'
|
|
238
241
|
: 'text-(--font-color) hover:bg-(--container-color)'
|
|
239
242
|
}
|
|
240
|
-
${option.disabled || disabled ? 'cursor-not-allowed text-(--faint-color)' : 'cursor-pointer'}
|
|
243
|
+
${option.disabled || disabled ? 'cursor-not-allowed text-(--faint-color)' : 'cursor-pointer'}
|
|
244
|
+
${fitContent ? 'px-3 whitespace-nowrap' : ''}`,
|
|
241
245
|
option.class,
|
|
242
246
|
)} {hasOwnColor ? 'bg-(--bg-color)' : selected ? 'bg-(--bg-color,var(--accent-color))' : 'bg-(--back-color)'}"
|
|
243
247
|
onclick={(e) => selectOption(option, e)}
|
package/dist/WidgetHeader.svelte
CHANGED
|
@@ -27,42 +27,57 @@
|
|
|
27
27
|
} = $props()
|
|
28
28
|
|
|
29
29
|
const Icon = $derived(icon)
|
|
30
|
+
|
|
31
|
+
/* Правая часть уходит второй строкой, если не помещается рядом с заголовком (место под значок, заголовок и «?») */
|
|
32
|
+
const TITLE_MIN_PX = 180
|
|
33
|
+
let headerWidth = $state(0)
|
|
34
|
+
let rightWidth = $state(0)
|
|
35
|
+
let wrapped = $derived(!!right && headerWidth > 0 && rightWidth + TITLE_MIN_PX + (hints ? 34 : 0) > headerWidth)
|
|
30
36
|
</script>
|
|
31
37
|
|
|
32
|
-
<!--
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
class="flex min-w-0 flex-1 cursor-pointer items-center gap-2 border-none bg-transparent p-0 text-left"
|
|
37
|
-
onclick={() => (collapsed = !collapsed)}
|
|
38
|
-
aria-expanded={!collapsed}
|
|
39
|
-
>
|
|
40
|
-
<span class="flex h-[18px] w-[18px] shrink-0 items-center justify-center text-(--accent-color) [&_svg]:h-full [&_svg]:w-full">
|
|
41
|
-
<Icon />
|
|
42
|
-
</span>
|
|
43
|
-
<span class="min-w-0 truncate text-[14px] font-semibold">{label}</span>
|
|
44
|
-
<span
|
|
45
|
-
class="flex h-[14px] w-[14px] shrink-0 items-center justify-center text-(--faint-color) transition-transform duration-150 [&_svg]:h-full [&_svg]:w-full"
|
|
46
|
-
style="transform: rotate({collapsed ? 0 : 90}deg)"
|
|
47
|
-
>
|
|
48
|
-
<ArrowIcon />
|
|
49
|
-
</span>
|
|
50
|
-
</button>
|
|
51
|
-
{#if right}
|
|
52
|
-
<div class="flex min-w-0 shrink-0 items-center justify-end">
|
|
53
|
-
{@render right()}
|
|
54
|
-
</div>
|
|
55
|
-
{/if}
|
|
56
|
-
{#if hints}
|
|
38
|
+
<!-- Первая строка фиксированной высоты 32 px — свёрнутые виджеты одной высоты; «?» — в правом краю.
|
|
39
|
+
Правая часть стоит в первой строке, а если не помещается — второй строкой под заголовком (выравнивание вправо) -->
|
|
40
|
+
<div class="flex flex-col gap-2" bind:clientWidth={headerWidth}>
|
|
41
|
+
<div class="flex h-[32px] items-center justify-between gap-3">
|
|
57
42
|
<button
|
|
58
43
|
type="button"
|
|
59
|
-
class="flex
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
: 'border-(--hairline-color) bg-transparent text-(--faint-color) hover:text-(--muted-color)'}"
|
|
63
|
-
title={$hints ? $T("widget.hints.on") : $T("widget.hints.off")}
|
|
64
|
-
aria-pressed={$hints}
|
|
65
|
-
onclick={() => hints.update((on) => !on)}>?</button
|
|
44
|
+
class="flex min-w-0 flex-1 cursor-pointer items-center gap-2 border-none bg-transparent p-0 text-left"
|
|
45
|
+
onclick={() => (collapsed = !collapsed)}
|
|
46
|
+
aria-expanded={!collapsed}
|
|
66
47
|
>
|
|
48
|
+
<span class="flex h-[18px] w-[18px] shrink-0 items-center justify-center text-(--accent-color) [&_svg]:h-full [&_svg]:w-full">
|
|
49
|
+
<Icon />
|
|
50
|
+
</span>
|
|
51
|
+
<span class="min-w-0 truncate text-[14px] font-semibold">{label}</span>
|
|
52
|
+
<span
|
|
53
|
+
class="flex h-[14px] w-[14px] shrink-0 items-center justify-center text-(--faint-color) transition-transform duration-150 [&_svg]:h-full [&_svg]:w-full"
|
|
54
|
+
style="transform: rotate({collapsed ? 0 : 90}deg)"
|
|
55
|
+
>
|
|
56
|
+
<ArrowIcon />
|
|
57
|
+
</span>
|
|
58
|
+
</button>
|
|
59
|
+
{#if right && !wrapped}
|
|
60
|
+
<div class="flex w-max shrink-0 items-center justify-end" bind:clientWidth={rightWidth}>
|
|
61
|
+
{@render right()}
|
|
62
|
+
</div>
|
|
63
|
+
{/if}
|
|
64
|
+
{#if hints}
|
|
65
|
+
<button
|
|
66
|
+
type="button"
|
|
67
|
+
class="flex size-[22px] shrink-0 cursor-pointer items-center justify-center rounded-full border text-[12px] font-bold transition-colors duration-150
|
|
68
|
+
{$hints
|
|
69
|
+
? 'border-(--accent-color) bg-(--accent-soft) text-(--accent-color)'
|
|
70
|
+
: 'border-(--hairline-color) bg-transparent text-(--faint-color) hover:text-(--muted-color)'}"
|
|
71
|
+
title={$hints ? $T("widget.hints.on") : $T("widget.hints.off")}
|
|
72
|
+
aria-pressed={$hints}
|
|
73
|
+
onclick={() => hints.update((on) => !on)}>?</button
|
|
74
|
+
>
|
|
75
|
+
{/if}
|
|
76
|
+
</div>
|
|
77
|
+
{#if right && wrapped}
|
|
78
|
+
<!-- Во второй строке элементы могут переноситься; естественная ширина правой части — из первой строки -->
|
|
79
|
+
<div class="flex max-w-full flex-wrap items-center justify-end gap-2">
|
|
80
|
+
{@render right()}
|
|
81
|
+
</div>
|
|
67
82
|
{/if}
|
|
68
83
|
</div>
|
|
@@ -129,7 +129,7 @@
|
|
|
129
129
|
<!-- Заголовок -->
|
|
130
130
|
<WidgetHeader icon={MemoryIcon} label={label?.name || $T("widget.stack.title")} bind:collapsed {hints}>
|
|
131
131
|
{#snippet right()}
|
|
132
|
-
<div class="flex items-center gap-2" use:hint={{ text: $T("widget.stack.hint.poll"), enabled: $hints }}>
|
|
132
|
+
<div class="flex flex-wrap items-center justify-end gap-2" use:hint={{ text: $T("widget.stack.hint.poll"), enabled: $hints }}>
|
|
133
133
|
<UI.Select
|
|
134
134
|
wrapperClass="w-64"
|
|
135
135
|
type="buttons"
|
package/dist/types.d.ts
CHANGED