poe-svelte-ui-lib 1.83.0 → 1.84.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.
Files changed (109) hide show
  1. package/README.md +114 -77
  2. package/dist/Accordion/Accordion.svelte +2 -4
  3. package/dist/Accordion/README.md +30 -124
  4. package/dist/Button/Button.svelte +3 -18
  5. package/dist/Button/README.md +37 -141
  6. package/dist/Carousel/Carousel.svelte.d.ts +1 -0
  7. package/dist/Carousel/README.md +24 -116
  8. package/dist/CommonSnippets.svelte +1 -1
  9. package/dist/CommonSnippets.svelte.d.ts +1 -1
  10. package/dist/CopiedChip.svelte +1 -6
  11. package/dist/Divider/Divider.svelte +1 -1
  12. package/dist/Divider/README.md +22 -91
  13. package/dist/Dragging.README.md +36 -52
  14. package/dist/Dragging.svelte +1 -4
  15. package/dist/FileAttach/FileAttach.svelte +2 -5
  16. package/dist/FileAttach/FileAttach.svelte.d.ts +1 -0
  17. package/dist/FileAttach/README.md +38 -150
  18. package/dist/Graph/README.md +39 -157
  19. package/dist/Input/Input.svelte +3 -10
  20. package/dist/Input/README.md +50 -152
  21. package/dist/Joystick/README.md +33 -114
  22. package/dist/Modal.README.md +32 -77
  23. package/dist/Modal.svelte +3 -8
  24. package/dist/PeriodChart/PeriodChart.svelte +2 -4
  25. package/dist/PeriodChart/README.md +41 -134
  26. package/dist/ProgressBar/ProgressBar.svelte +1 -2
  27. package/dist/ProgressBar/README.md +30 -122
  28. package/dist/PropsGroup.svelte +1 -5
  29. package/dist/PropsListHeader.svelte +1 -2
  30. package/dist/PropsListModal.svelte +2 -4
  31. package/dist/Select/README.md +54 -155
  32. package/dist/Select/Select.svelte +4 -18
  33. package/dist/Slider/README.md +30 -142
  34. package/dist/Slider/Slider.svelte +7 -38
  35. package/dist/Switch/README.md +38 -156
  36. package/dist/Switch/Switch.svelte +2 -7
  37. package/dist/Table/README.md +70 -238
  38. package/dist/Table/TableProps.svelte +2 -4
  39. package/dist/Table/columnWidth.js +1 -2
  40. package/dist/Tabs/README.md +41 -152
  41. package/dist/Tabs/Tabs.svelte +3 -18
  42. package/dist/Tabs/Tabs.svelte.d.ts +1 -0
  43. package/dist/Tabs/TabsProps.svelte +1 -4
  44. package/dist/TextField/README.md +23 -89
  45. package/dist/TextField/TextField.svelte +2 -4
  46. package/dist/TextsEditor.svelte +1 -3
  47. package/dist/Tooltip.svelte +1 -7
  48. package/dist/VideoViewer/README.md +35 -133
  49. package/dist/VideoViewer/VideoViewer.svelte +1 -5
  50. package/dist/VideoViewer/VideoViewer.svelte.d.ts +1 -0
  51. package/dist/Widget/README.md +42 -175
  52. package/dist/Widget/Widget.svelte +2 -6
  53. package/dist/Widget/WidgetProps.svelte +1 -3
  54. package/dist/WidgetAccentPicker.svelte +1 -3
  55. package/dist/WidgetDeviceInfo/README.md +50 -81
  56. package/dist/WidgetDeviceInfo/WidgetDeviceInfo.svelte +4 -18
  57. package/dist/WidgetDeviceInfo/WidgetDeviceInfo.svelte.d.ts +2 -2
  58. package/dist/WidgetDeviceInfo/WidgetDeviceInfoProps.svelte +1 -4
  59. package/dist/WidgetFileSystem/README.md +61 -88
  60. package/dist/WidgetFileSystem/WidgetFileSystem.svelte +2 -8
  61. package/dist/WidgetFileSystem/WidgetFileSystem.svelte.d.ts +2 -2
  62. package/dist/WidgetFileSystem/WidgetFileSystemProps.svelte +1 -4
  63. package/dist/WidgetHeader.svelte +2 -9
  64. package/dist/WidgetMap/README.md +61 -67
  65. package/dist/WidgetMap/WidgetMap.svelte +27 -7
  66. package/dist/WidgetMap/WidgetMapProps.svelte +8 -3
  67. package/dist/WidgetMap/mapWrapper/Line.svelte +1 -1
  68. package/dist/WidgetMap/mapWrapper/utils.js +2 -2
  69. package/dist/WidgetPFD/README.md +134 -114
  70. package/dist/WidgetPFD/WidgetPFD.svelte +18 -7
  71. package/dist/WidgetPFD/WidgetPFDProps.svelte +9 -3
  72. package/dist/WidgetRGBStrip/README.md +52 -58
  73. package/dist/WidgetRGBStrip/WidgetRGBStrip.svelte +1 -4
  74. package/dist/WidgetRGBStrip/WidgetRGBStrip.svelte.d.ts +2 -2
  75. package/dist/WidgetRGBStrip/WidgetRGBStripProps.svelte +1 -2
  76. package/dist/WidgetStackInfo/README.md +52 -58
  77. package/dist/WidgetStackInfo/WidgetStackInfo.svelte +1 -4
  78. package/dist/WidgetStackInfo/WidgetStackInfo.svelte.d.ts +2 -2
  79. package/dist/WidgetStackInfo/WidgetStackInfoProps.svelte +1 -4
  80. package/dist/WidgetWiFi/README.md +47 -77
  81. package/dist/WidgetWiFi/WidgetWiFi.svelte +7 -29
  82. package/dist/WidgetWiFi/WidgetWiFi.svelte.d.ts +2 -2
  83. package/dist/WidgetWiFi/WidgetWiFiProps.svelte +1 -3
  84. package/dist/bitField.js +1 -2
  85. package/dist/dragStyle.js +2 -6
  86. package/dist/flightSim.d.ts +6 -0
  87. package/dist/flightSim.js +131 -0
  88. package/dist/hints.js +3 -6
  89. package/dist/index.js +1 -0
  90. package/dist/locales/i18n.js +3 -8
  91. package/dist/locales/index.js +1 -2
  92. package/dist/locales/languages.js +1 -5
  93. package/dist/locales/localize.js +2 -3
  94. package/dist/locales/translations.js +2 -3
  95. package/dist/options.js +2 -9
  96. package/dist/protocols/PROTOCOL.md +96 -71
  97. package/dist/protocols/can.js +2 -5
  98. package/dist/protocols/cbor/json.js +1 -0
  99. package/dist/protocols/dictionary.js +1 -4
  100. package/dist/protocols/dictionary.yaml +1 -3
  101. package/dist/protocols/index.js +1 -2
  102. package/dist/protocols/packet.js +2 -4
  103. package/dist/protocols/plotGroups.js +1 -2
  104. package/dist/protocols/xPoeDebug.js +1 -2
  105. package/dist/theme.css +9 -31
  106. package/dist/types.d.ts +2 -0
  107. package/dist/widgetAccent.js +3 -9
  108. package/dist/widgetCollapse.js +1 -4
  109. package/package.json +6 -2
package/README.md CHANGED
@@ -1,35 +1,36 @@
1
1
  # poe-svelte-ui-lib
2
2
 
3
- Библиотека компонентов на Svelte 5 (руны) для интерфейсов устройств компании. Один и тот же компонент выглядит и ведёт себя одинаково везде, где он используется:
3
+ Библиотека компонентов на Svelte 5 для интерфейсов устройств. Её используют три приложения, и компонент в каждом выглядит и работает одинаково:
4
4
 
5
- - **DevCloud** — облако: конструктор GUI устройства, панель управления, документация;
6
- - **WebApp** — локальный веб-интерфейс прошивок ProdFactory-ESP, встроенный в устройство;
7
- - **DevTerminal** — настольный терминал разработчика.
5
+ - **DevCloud** - облако: конструктор интерфейса устройства, панель управления, отладка;
6
+ - **WebApp** - веб-интерфейс, который прошивка ProdFactory-ESP раздаёт с самого устройства;
7
+ - **DevTerminal** - настольный терминал для отладки через COM-порт.
8
+
9
+ Кроме компонентов, в библиотеке лежат ядро протоколов обмена с устройством, общий словарь команд, тема и переводы. Приложения не держат своих копий, всё берут отсюда.
8
10
 
9
11
  Витрина с живыми примерами: [oleg-perevyshin.github.io/ElementsUI](https://oleg-perevyshin.github.io/ElementsUI/).
10
12
 
11
- ## Состав
13
+ ## Что внутри
14
+
15
+ **Смарт-виджеты.** Готовые блоки под одну задачу. Виджет сам работает с группой полей прошивки по префиксу, привязывать переменные по одной не нужно.
12
16
 
13
- **Смарт-виджеты** — готовые блоки под конкретную задачу, работают с группой полей прошивки по префиксу, переменные привязывать не нужно; шапка со сворачиванием и мастер-цветом:
17
+ - `WidgetWiFi` - режим сети, подключение к точке доступа, своя точка доступа, поиск сетей.
18
+ - `WidgetDeviceInfo` - паспорт устройства, основные настройки, перезагрузка.
19
+ - `WidgetFileSystem` - занятая память, список файлов, загрузка и удаление.
20
+ - `WidgetStackInfo` - свободная память и запас стека задач, для отладки.
21
+ - `WidgetRGBStrip` - адресная светодиодная лента: цвет, эффекты, параметры.
22
+ - `WidgetPFD` - пилотажный дисплей: авиагоризонт, шкалы скорости и высоты, маршрут, сообщения автопилота.
23
+ - `WidgetMap` - карта с объектами и их траекториями.
14
24
 
15
- - `WidgetWiFi` — настройка сети: режим, клиент, точка доступа, поиск сетей;
16
- - `WidgetDeviceInfo` — паспорт устройства и основные настройки, перезагрузка;
17
- - `WidgetFileSystem` — память, список файлов, удаление и закачка;
18
- - `WidgetStackInfo` — отладка: свободная память и запас стека задач;
19
- - `WidgetRGBStrip` — адресная светодиодная лента: цвет, эффекты, параметры ленты;
20
- - `WidgetPFD` — пилотажный дисплей: авиагоризонт, ленты, маршрут, связь, сообщения автопилота;
21
- - `WidgetMap` — карта объектов с траекториями, несколько групп-объектов на одной карте.
25
+ **Компоненты.** Каждый привязывается к одной переменной устройства: `Input`, `Select`, `Switch`, `Slider`, `Button`, `Joystick`, `ProgressBar`, `Graph`, `PeriodChart`, `Table`, `FileAttach`, `VideoViewer`, `TextField`, `Widget`.
22
26
 
23
- **Компоненты** — привязываются к одной переменной устройства: `Input`, `Select`, `Switch`, `Slider`, `Button`, `Joystick`, `ProgressBar`, `Graph`, `PeriodChart`, `Table`, `FileAttach`, `VideoViewer`, `TextField`, `Widget` (карточка одного значения).
27
+ **Раскладка.** `Accordion`, `Tabs`, `Divider`, `Carousel`, `Modal`.
24
28
 
25
- **Раскладка** — `Accordion`, `Tabs`, `Divider`, `Carousel`, `Modal`.
29
+ **Ядро протоколов** (`poe-svelte-ui-lib/protocols`). Кодирование и разбор пакетов для всех каналов связи с устройством. Работает без Svelte, в том числе под Node.
26
30
 
27
- ## Как устроено
31
+ **Тема** (`poe-svelte-ui-lib/theme.css`) и **языки** (`poe-svelte-ui-lib/locales`).
28
32
 
29
- - **Компонент только отображает и сообщает.** Он получает значения через пропсы и отдаёт изменения колбэками (`onUpdate`, `onChange`, `onSave`…). С сетью, WebSocket и `DeviceStore` работает приложение (`GUIPreview` в DevCloud и WebApp): значения переменных устройства хранятся под ключами `<ModSN>|<ключ>`, смарт-виджеты читают свою группу (`MAV.Lat`, `CFG.DevName`…).
30
- - **Конструктор свойств.** У каждого компонента есть `<Компонент>Props.svelte` — панель свойств для конструктора DevCloud.
31
- - **Описания.** Короткое описание (i) — `component.info.<Тип>` в переводах (ru/en/zh), его показывают конструктор облака и витрина; развёрнутое — README рядом с исходником компонента.
32
- - **Тема** — один файл `poe-svelte-ui-lib/theme.css` для всех приложений: палитра светлой и тёмной темы, типографика, Markdown, роли заливки.
33
+ Полный список экспортов в `src/lib/index.ts`. У каждого компонента рядом с исходником есть свой README с пропсами и примерами.
33
34
 
34
35
  ## Установка
35
36
 
@@ -37,41 +38,73 @@
37
38
  npm install poe-svelte-ui-lib
38
39
  ```
39
40
 
40
- ### Требования (peerDependencies)
41
-
42
- - `svelte ^5.0.0`
43
- - `tailwindcss ^4.0.0` — компоненты стилизуются Tailwind-утилитами и CSS-переменными темы; сама тема поставляется файлом `theme.css`
41
+ Приложению нужны `svelte` 5 и `tailwindcss` 4. Компоненты стилизуются утилитами Tailwind и переменными темы.
44
42
 
45
- ### Подключение стилей и темы
46
-
47
- Тема поставляется пакетом — `poe-svelte-ui-lib/theme.css`: цветовые токены светлой и тёмной темы (`--back-color`, `--accent-color`, `--red-color`…), типографика тегов в `@layer base`, компактный Markdown (`.markdown-content` — обёртка для `{@html}` с результатом `RenderMarkdown`) и роли заливки `bg-*`/`border-*`. Эталон темы — DevCloud; витрина подключает тот же файл, поэтому компоненты в ней выглядят ровно как в облаке. В `app.css` потребителя:
43
+ В `app.css` приложения:
48
44
 
49
45
  ```css
50
46
  @import "tailwindcss";
51
47
  @import "poe-svelte-ui-lib/theme.css";
52
48
  @source "../node_modules/poe-svelte-ui-lib/dist";
53
49
  @custom-variant dark (&:where(.dark, .dark *));
50
+ ```
54
51
 
55
- /* дальше — только собственные отличия приложения, например :root { min-width: 640px; } */
52
+ Ниже можно дописать только то, чем приложение отличается от остальных.
53
+
54
+ ## Как пользоваться
55
+
56
+ ```svelte
57
+ <script lang="ts">
58
+ import * as UI from "poe-svelte-ui-lib"
59
+
60
+ let value = $state("")
61
+ </script>
62
+
63
+ <UI.Input label={{ name: "Имя" }} bind:value type="text" />
64
+ <UI.Button content={{ name: "Сохранить" }} onClick={() => console.log(value)} />
56
65
  ```
57
66
 
58
- **Поверхности — четыре ступени, заметные в обеих темах:** фон страницы `--bg-body` → панель `--back-color` → блок внутри панели `--container-color` → поле `--field-color` (в тёмной теме поле темнее блока — «утоплено»). Готовые рецепты — классы `ui-panel` (блок прямо на фоне страницы: карточка, шапка раздела, холст, область чата — заливка панели, волосяная рамка, лёгкая тень) и `ui-inset` (блок внутри панели: группа полей, шапка карточки, подложка сообщения). Отступы и скругление задаёт страница классами Tailwind. Панели не делаются полупрозрачными (`bg-(--back-color)/50` сливается с фоном): выпадающие меню и всплывающие блоки — `ui-panel` с тенью `--elevation-3`, свои сообщения в чатах — `--accent-soft`, чужие — `--container-color`.
67
+ Главное правило: компонент только показывает данные и сообщает об изменениях. Значения приходят через пропсы, изменения уходят колбэками (`onUpdate`, `onChange`, `onSave` и другие). Сетью, WebSocket и хранилищем значений занимается приложение.
68
+
69
+ В DevCloud и WebApp значения устройства хранятся под ключами вида `<ModSN>|<ключ>`. Смарт-виджет читает свою группу целиком, например все поля `CFG.*` или `MAV.*`.
70
+
71
+ У каждого компонента есть парный `<Компонент>Props.svelte`. Это панель свойств для конструктора DevCloud. Пропсы у всех панелей одинаковые:
72
+
73
+ | Пропс | Что это |
74
+ |---|---|
75
+ | `component` | Компонент интерфейса и его свойства |
76
+ | `onPropertyChange` | Сообщает об изменении свойств, имени, доступа или события |
77
+ | `forConstructor` | `true` — полная панель конструктора, `false` — упрощённая для редактирования |
59
78
 
60
- **Названия смарт-виджетов** — в словаре библиотеки на всех языках (WiFi, «Об устройстве», «Файловая система», «Стек и задачи», «RGB лента», «Пилотажный дисплей», «Карта»); пустой `label.name` показывает название на языке пользователя, `widgetTitle(type)` отдаёт его сразу на всех языках `{ ru, en, zh }` — так конструктор заполняет заголовок нового виджета.
79
+ ## Протоколы
61
80
 
62
- **Битовые поля конфигурации** — `bitFieldGet(word, start, end)`/`bitFieldSet(word, start, end, value)`: поле `start..end` 32-битного слова `{GROUP}.Cfg` (Select/Input с `bitMode`) обычной арифметикой, без знаковых 32-битных операций JS — бит 31 разбирается и собирается корректно, результат всегда 0..2³²−1; тест против эталона на BigInt — `tests/bitField.test.mjs`.
81
+ Пакет `poe_cbor_pkt` один для CAN, CAN FD, RS485 и UART-консоли. В нём адрес получателя, адрес отправителя, команда и данные в CBOR. Библиотека умеет:
63
82
 
64
- **Ядро протоколов** — `poe-svelte-ui-lib/protocols`, описание протокола — [`src/lib/protocols/PROTOCOL.md`](src/lib/protocols/PROTOCOL.md) (без Svelte, работает и под Node без Vite): общий для DevCloud, WebApp и DevTerminal CBOR-кодек (RFC 8949); `valueToCbor`/`cborToValue` — обычные значения, двоичные данные как `Uint8Array` (WebSocket, хранилище, телеметрия); `jsonToCbor` — JSON-совместимое значение в CBOR, строки base64 под ключами с `BIN` — байты (поля ввода терминала и отладки). Пакет `poe_cbor_pkt` — indefinite-массив объектов `[[TrgBusID, SrcBusID, HAR, Payload, CRC16], …]` (CAN, RS485, UART-консоль), `Payload` — одно CBOR item (сырые данные — `encodePacketBytesPayload`, пустой массив — `null`): `encodePacket`/`decodePacket` (разбор с начала буфера — `complete` с длиной, `incomplete` для потока или `garbage`; объекты одному адресату не склеиваются, порядок сохраняется, неверный CRC — флаг `crcOk`), `BUS_ID_REGEXP`/`parseBusId`/`formatBusId` — поля BusID в HEX и вывод `0x0000`, `makeHar(header, argument, reply = true)`/`splitHar` — `HAR`: заголовок в битах 14-15, аргумент в битах 1-13 (0..8191), флаг ответа в бите 0 (как `HAR`/`HAR_NR` прошивки), `packetObjectCrc`; контрольная сумма `crc16Kermit` — строго побайтная, как в `common.c` прошивок. Байты совпадают с `poe_cbor_pkt.c` прошивки — проверка `npm run TestProtocols` (`tests/protocols.test.mjs`, эталонные пакеты собраны прошивочным кодом). Протокол xPOE-Debug (UART-консоль `system_console`) — тот же пакет `poe_cbor_pkt` вперемешку с текстом загрузчика: `encodeXPoeDebugFrame(header, argument, payload, srcId, trgId, reply)` кодирует запрос, `xPoeDebugHar` — HAR по именам словаря, `createXPoeDebugParser().push(байты)` разбирает поток пакетов (каждая запись — отдельный элемент) и внешний текст (`raw`), логи `OK! DebugLog` — `[уровень, тег, текст, FHS]` (`DEBUG_LOG_ARGUMENT`, FHS — в `freeHeap`). Строка таблицы — `xPoeDebugRow`, колонки — `xPoeDebugTableColumns` (основной вход библиотеки): общие для отладки облака и терминала. Ячейка Value — `formatXPoeDebugValue` (CBOR одной строкой, `DebugLog` — уровень · тег · текст), окно по клику — `formatXPoeDebugModal`: Value в развёрнутом виде (`formatXPoeDebugPretty` — то же чистым текстом; карты и массивы с отступами, `DebugLog` — уровень и тег, ниже текст или дамп и FHS) в цветах палитры темы — ключи `--pink-color`, строки `--purple-color`, числа `--red-color`, логические `--orange-color`, `null` — `--cyan-color`, байты `--green-color`, HEX — исходные байты `Payload` сплошной строкой; числа float32 выводятся кратчайшей записью (`0.12`). CAN/CAN FD через slcan-адаптер (`can_service` прошивки): `canFragments`/`encodeCanPacket` — нарезка пакета на кадры как `CAN_Send` (бит 10 ID — «последний», биты 0..9 — `packetId`, по 8 / 64 байта), `encodeSlcanFrame`, `createCanParser().push(байты)` — разбор кадров slcan со сборкой фрагментов и обрезкой паддинга CAN FD. RS485 — сырой поток пакетов: `createPacketStreamParser().push(байты)` (пауза обрывает недособранное, мусор пропускается по байту). Открытие slcan-адаптера — `slcanOpenCommands(скорость, скоростьДанных?)`. Поле Value команды xPOE-Debug из ввода — `xPoeDebugValueFromText` (hex как есть, JSON → CBOR, пусто — пустой Payload). Графики отладки — пакет `OK! DebugPlot` (`LOG_PLOT` прошивки, `DEBUG_PLOT_ARGUMENT`): `debugPlotValues(value)` — пары `[имя, число]` из HEX CBOR-карты `Payload`, `createPlotGroups().update(пары)` раскладывает по группам (префикс до точки) в порядке карты и возвращает обновлённые группы, `data(группа)` — последние значения. Словарь протокола — `HEADER_CODES`, `DEFAULT_ARGUMENT_CODES` (генерируется из мастер-словаря `src/lib/protocols/dictionary.yaml` — `npm run Dictionary`, перед упаковкой автоматически; сам файл поставляется как `poe-svelte-ui-lib/protocols/dictionary.yaml`, `.framework/Dictionary.yaml` прошивок — его справочные копии, сборка прошивок сверяет с ними `api_har.h`), `parseArgumentDictionary` (строки `- [Строка, Enum, Число]`), `nameByCode`. Своих копий протоколов и словаря в приложениях не держим: терминал и отладка облака читают и пишут порт сырыми байтами, разбор и сборка — здесь.
83
+ - собирать и разбирать пакеты, считать CRC;
84
+ - резать пакет на кадры CAN и CAN FD и собирать обратно, общаться со slcan-адаптером;
85
+ - разбирать поток консоли xPOE-Debug, где пакеты идут вперемешку с текстом загрузчика;
86
+ - показывать отладочные логи `DebugLog` и графики `DebugPlot` из прошивки;
87
+ - переводить значения между JSON и CBOR.
65
88
 
66
- **Шапка смарт-виджета** (`WidgetHeader`): значок, заголовок и сворачивание слева, «?» в правом краю; правая часть (режимы, «Обновить» и т. п.) стоит в той же строке, а если не помещается — уходит второй строкой под заголовок и там переносится.
89
+ Байты совпадают с тем, что собирает прошивка. Это проверяет `npm run TestProtocols`: тесты сверяют результат с эталонными пакетами, собранными кодом прошивки.
67
90
 
68
- **Подсказки смарт-виджетов** — `hints.ts`: у каждого виджета своя кнопка «?» в правом краю шапки (`WidgetHeader` с пропом `hints`), по умолчанию подсказки выключены, выбор оператора запоминается в браузере для виджетов этого типа (`hintsSetting("WidgetPFD")`, ключ `localStorage` `WidgetHints.<тип>`, пишется только по нажатию «?»), глобального переключателя нет. Элемент получает подсказку действием `use:hint={{ text, enabled: $hints }}` — всплывающее окно в стиле темы над элементом; тексты — в словаре библиотеки (`widget.*.hint.*`), только там, где смысл поля не очевиден.
91
+ Формат пакета, адресация, транспорты и список функций описаны в [PROTOCOL.md](src/lib/protocols/PROTOCOL.md).
69
92
 
70
- **Предпросмотр темы** — вкладка «Тема» на главной витрины (`src/routes/ThemePreview.svelte`): палитра токенов и состояния, затем все компоненты и виджеты в порядке меню витрины — каждый тип в своём разделе с живыми демо-данными (графики, видео, полёт для PFD и карты), в конце типографика и Markdown; тема переключается кнопкой в шапке витрины. Правьте `theme.css` и смотрите результат там.
93
+ ## Словарь команд
71
94
 
72
- Текст в Markdown, таблицы и код переносятся по ширине контейнера — горизонтальной прокрутки быть не должно, только вертикальная. Markdown рендерится с `breaks: true` (как в облаке), поэтому абзац и пункт списка пишутся одной строкой — ручной перенос внутри абзаца превращается в разрыв строки.
95
+ Все команды (`GET`, `SET`, `ModCfg`, `Restart` и остальные) записаны в одном файле `src/lib/protocols/dictionary.yaml`. Из него генерируется `DEFAULT_ARGUMENT_CODES` для JS (`npm run Dictionary`, перед публикацией запускается сам).
73
96
 
74
- **Глобальные стили тегов — только в `@layer base`.** Компоненты задают размеры текста и отступы Tailwind-утилитами (например `text-[12px]` у подписи `<h5>`). Правило вне слоя (`h5 { font-size: 1rem }`, `label { … }`, `p { … }`) сильнее любой утилиты, и в приложении подписи станут крупнее задуманного и перестанут помещаться. Поэтому типографику тегов оборачивайте:
97
+ Прошивки ProdFactory-ESP и ProdFactory-STM держат копию словаря в `.framework/Dictionary.yaml`. При сборке прошивки она сверяется с `api_har.h`. Новую команду сначала добавляют сюда, потом копируют в оба фреймворка.
98
+
99
+ ## Тема
100
+
101
+ Тема одна для всех приложений. Эталоном служит DevCloud, витрина подключает тот же файл.
102
+
103
+ Поверхности идут в четыре ступени: фон страницы `--bg-body`, панель `--back-color`, блок внутри панели `--container-color`, поле ввода `--field-color`. Для частых случаев есть готовые классы. `ui-panel` для блока прямо на фоне страницы, `ui-inset` для блока внутри панели.
104
+
105
+ Панели не делают полупрозрачными, на фоне они теряются. Выпадающие меню делают через `ui-panel` с тенью `--elevation-3`.
106
+
107
+ Стили тегов в приложении пишите только внутри `@layer base`. Правило вне слоя сильнее утилит Tailwind, и подписи в компонентах станут крупнее, чем задумано.
75
108
 
76
109
  ```css
77
110
  @layer base {
@@ -79,74 +112,78 @@ npm install poe-svelte-ui-lib
79
112
  font-size: 1rem;
80
113
  font-weight: 600;
81
114
  }
82
- label {
83
- font-size: 0.8rem;
84
- }
85
115
  }
86
116
  ```
87
117
 
88
- Классы ролей (`.bg-red`, `.bg-max`, …) и темы (`.light`/`.dark`) остаются вне слоя — они как раз должны перебивать утилиты.
118
+ Классы ролей (`.bg-red`, `.bg-max` и другие) и классы темы (`.light`, `.dark`) остаются вне слоя. Они как раз должны перебивать утилиты.
89
119
 
90
- Необязательный токен `--table-header-color` — фон шапки `Table` (по умолчанию `--container-color`); смарт-виджеты задают его сами из мастер-цвета.
120
+ Шапку `Table` можно перекрасить переменной `--table-header-color`. По умолчанию она `--accent-soft`, смарт-виджеты задают её сами от своего цвета.
91
121
 
92
- Справочник по регулярным выражениям для проверки полей ввода — вкладка «Регулярные выражения» на главной витрины (`src/routes/RegExp.md`). Протокол обмена с устройством описан в документации DevCloud (разделы «Протокол устройства» и «Обмен данными с устройством»).
122
+ Посмотреть всю тему разом можно на вкладке «Тема» на главной витрины. Там палитра, все компоненты с демо-данными, типографика и Markdown.
93
123
 
94
- ## Использование
124
+ ## Языки
95
125
 
96
- ```svelte
97
- <script lang="ts">
98
- import * as UI from "poe-svelte-ui-lib"
126
+ Список языков задан в одном месте, `LANGUAGES` в `src/lib/locales/languages.ts`. Сейчас это RU, EN и ZH. Чтобы добавить язык, достаточно одной записи там. Переключатели языка во всех приложениях подхватят его сами. Пока перевода нет, показывается русский текст.
99
127
 
100
- let value = $state("")
101
- </script>
128
+ Приложения не держат свой список языков. Они берут его из библиотеки, а свой словарь подключают так:
102
129
 
103
- <UI.Input label={{ name: "Имя" }} bind:value type="text" />
104
- <UI.Button content={{ name: "Сохранить" }} onClick={() => console.log(value)} />
130
+ ```ts
131
+ export const T = createTranslator(translations)
105
132
  ```
106
133
 
107
- Полный список компонентов и типов — в `src/lib/index.ts`. У каждого компонента есть README рядом с исходником (`src/lib/<Component>/README.md`, для `Modal`/`Dragging` — `src/lib/<Component>.README.md`) с описанием пропсов, примерами и внутренним устройством; живая витрина — `npm run dev`: на главной вкладки «Обзор» (этот README), «Тема» (предпросмотр `theme.css`) и «Регулярные выражения», дальше страница на каждый компонент.
108
-
109
- **Витрина повторяет конструктор DevCloud:** слева компонент и код (прижат к низу), справа панель свойств шириной `24rem` с тем же оформлением, что в облаке, — переполнение подписей видно сразу. Кнопка (i) в шапке панели открывает описание компонента.
134
+ Один вызов `setLanguage` переключает язык и в библиотеке, и в приложении. Выбор сохраняется в браузере. В SSR-приложениях сохранённый язык восстанавливают вызовом `restoreLanguage()` в `onMount` корневого layout.
110
135
 
111
- **Описания компонентов (i)** — ключи `component.info.<Тип>` в `src/lib/locales/translations.ts` (ru/en/zh, Markdown). Один источник для витрины и конструктора DevCloud: облако показывает кнопку (i) у любого компонента, для которого есть описание. Добавляя компонент, допишите описание строго по шаблону — разделы всегда в этом порядке, неприменимые опускаются:
136
+ Серверный код, который запускается под Node без Vite, импортирует языки из `poe-svelte-ui-lib/locales`. Корень пакета тянет Svelte-компоненты, и Node его не загрузит.
112
137
 
113
- | Раздел | Что писать |
114
- | --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
115
- | `🎯 **Назначение**` | 1–2 фразы: что это и когда применять |
116
- | `📦 **Пакет данных**` | откуда данные (переменная, группа полей, объект ответа), каким пакетом и как часто их слать, что и когда компонент отправляет сам или «только отображение»; не связан с устройством — так и написать |
117
- | `🔑 **Ключи**` | по пункту на ключ: `` `Ключ` — тип, единицы, смысл``, обязательность; у простых компонентов — формат значения переменной |
118
- | `✨ **Особенности**` | поведение, ограничения, советы, связь с другими компонентами |
119
- | `⚙️ **Настройки**` | что меняется в панели свойств |
138
+ Тексты бывают двух видов:
120
139
 
121
- Пункты — списком `- `, без вложенных списков; имена ключей и значения — в обратных кавычках; одинаковые для нескольких виджетов ключи (`Lat`, `Lon`, `DevName`...) описываются одинаково.
140
+ - **Встроенные тексты компонентов**: подписи, кнопки, подсказки. Они только в словаре `src/lib/locales/translations.ts` и выводятся через `$T("ключ")`. Русских строк прямо в разметке быть не должно.
141
+ - **Тексты из конструктора**: название поля, варианты списка, заголовки колонок. Это строка или объект `{ ru, en, zh }`. Приложение переводит всё описание интерфейса функцией `localizeDeep` перед показом. В конструкторе их правят в окне «Тексты и переводы», которое есть у каждого компонента.
122
142
 
123
- **README компонента** (`src/lib/<Компонент>/README.md`, вкладка «Инфо» витрины) — развёрнутая документация для разработчика. Первые разделы повторяют описание (i) и не должны ему противоречить, дальше идут разработческие: `## Назначение` (плюс заметка о размерах) → `## Пакет данных` (плюс `### Протокол устройства` / пример кода прошивки) → `## Ключи` (таблица «Ключ / Описание», те же формулировки, что в (i)) → `## Особенности` (поведение, ограничения) → `## Пропсы` (таблица «Название / Тип / По умолчанию / Описание», колбэки — `### Колбэки`) → `## Примеры` (Svelte) → `## Конструктор свойств (<Компонент>Props.svelte)` → `## Внутреннее устройство`.
143
+ ## Как описывать компонент
124
144
 
125
- **Языки — единственный источник в библиотеке.** Список языков — `LANGUAGES` в `locales/languages.ts`: код, название и флаг (SVG-строка), без Svelte — годится и для серверного кода. **Новый язык — одна запись в `LANGUAGES`**: переключатели языка во всех приложениях (`LOCALES`), колонки окна «Тексты и переводы», многоязычные тексты GUI и словари подхватывают его сами; пока перевода нет — показывается текст языка по умолчанию (`DEFAULT_LANGUAGE`, `ru`). Словари (`Translations`) — строки-объекты по кодам `{ ru: "…", en: "…", zh: "…" }`: обязателен только язык по умолчанию, порядок не важен; недостающие переводы показывает `findMissingTranslations(словарь)`. `locales/i18n.ts` — текущий язык `Language`/`setLanguage` (неизвестный код не применяется, выбор сохраняется в `localStorage` `AppLanguage`), `restoreLanguage()` (сохранённый или язык браузера; стартовое значение всегда язык по умолчанию — серверный рендер совпадает с гидратацией, поэтому SSR-приложения вызывают его в `onMount` корневого layout, SPA — при старте), `LOCALES` (с флагом `flag`) и механизм перевода `createTranslator(словарь)`. Код вне компонентов берёт текущий язык через `getLanguage()` (например, для заголовка `Accept-Language`), ключ хранилища и язык по умолчанию в приложениях не повторяются; серверный код переводит функцией `translate(словарь, язык, ключ)` на язык запроса, разобранный `resolveLanguage(Accept-Language)`. Серверный код, который Node запускает без Vite (например WebSocket-сервер облака через `tsx`), импортирует языки и перевод из `poe-svelte-ui-lib/locales` — корень пакета экспортируется только для Svelte (условие `svelte`) и тянет компоненты, Node его не загрузит. Приложения (DevCloud, WebApp, терминал) свой список языков, хранилище и функцию перевода не держат: берут их из библиотеки и строят свой `$T` из своего словаря — `export const T = createTranslator(translations)`. Одно `setLanguage` переключает и компоненты библиотеки, и приложение. Многоязычные тексты GUI распознаются по виду ключей (коды языков), поэтому данные с языком, убранным из списка, не ломаются.
145
+ У компонента два описания.
126
146
 
127
- **Языки (ru/en/zh) — два слоя:**
147
+ **Короткое**, по кнопке (i). Лежит в словаре под ключом `component.info.<Тип>`. Его показывают витрина и конструктор DevCloud. Разделы идут в таком порядке, ненужные пропускаются:
128
148
 
129
- - **Встроенные тексты компонентов** (подписи полей виджетов, кнопки, подсказки, `aria-label`) — только через словарь `src/lib/locales/translations.ts` и `$T("ключ")`; строка с числами — параметрами: `$T("widget.fs.files", { n: files.length })` на ключ `"Файлов: {n}"`. Русских литералов в разметке и скриптах компонентов быть не должно. Списки вариантов с подписями — `$derived`, иначе не переключатся при смене языка. Исключение — шкалы прибора `WidgetPFD`: там общепринятые авиационные сокращения (`SPD`, `ALT`, `AS`, `VS`, `NO DATA`) на всех языках, переводятся только подсказки и строки состояния.
130
- - **Тексты, введённые в конструкторе** (`label.name`, `placeholder`, `options[].name`, вкладки, заголовки колонок, подписи переключателя и т.п.) — тип `LocalizedText` (`locales/localize.ts`): простая строка (только `ru`) или объект `{ ru, en, zh }`; при отсутствии перевода показывается `ru`, затем первый непустой. Компоненты получают уже готовые строки: приложение разрешает описание GUI функцией `localizeDeep(UIBlocks, язык)` перед рендером. Окна свойств (`*Props.svelte`) тексты не показывают и не правят — у каждого компонента одна кнопка «Тексты и переводы» (`TextsEditor`): модальное окно само собирает все тексты компонента (`collectTexts` по полям `name`, `label`, `labels`, `placeholder`, `text`, `info`, `title`, `captionLeft`/`captionRight`, `units`/`unit`, `footer`, `hiddenInfo`, `alt`; технические `id`, `class`, `icon`, `keys`, данные — никогда; у `Switch` варианты — короткие метки битов битового режима, их имя правится в окне свойств и не переводится — `NOT_TEXTS` в `TextsEditor.svelte`) и даёт по три поля RU/EN/ZH. Сохранение (`packLocalized`): пусто — `""`, только RU — строка, иначе объект из заполненных языков. Читая текст в окне свойств для логики, берите `localizeText(поле, "ru")` — поле может быть объектом. Заголовок смарт-виджета по умолчанию пустой — виджет показывает своё название из словаря на текущем языке.
149
+ | Раздел | Что писать |
150
+ |---|---|
151
+ | Назначение | Одна-две фразы: что это и когда применять |
152
+ | Пакет данных | Откуда данные, каким пакетом и как часто их слать, что компонент отправляет сам |
153
+ | Ключи | По пункту на ключ: тип, единицы, смысл |
154
+ | Особенности | Поведение, ограничения, советы |
155
+ | Настройки | Что меняется в панели свойств |
131
156
 
132
- **Иконки вариантов панелей свойств** — `src/lib/libIcons/propsIcons.ts` (контурные SVG 24×24 строками), подставляются в `IOption.icon` в `options.ts`.
157
+ **Подробное**, `src/lib/<Компонент>/README.md`. Оно открывается на вкладке «Инфо» витрины. Начало повторяет короткое описание и не должно ему противоречить. Дальше идут пропсы, примеры, панель свойств и внутреннее устройство.
133
158
 
134
159
  ## Разработка
135
160
 
136
161
  ```bash
137
- npm run dev # витрина компонентов (SvelteKit dev-сервер)
138
- npm run build # сборка пакета (svelte-kit sync + svelte-package + publint) → dist/
139
- npm run Formatting # prettier --write .
162
+ npm run dev # витрина на локальном сервере
163
+ npm run check # проверка типов
164
+ npm run TestProtocols # тесты протоколов и битовых полей
165
+ npm run Formatting # prettier
166
+ npm run build # сборка витрины в docs/
167
+ npm pack # сборка пакета в dist/ с проверками
140
168
  ```
141
169
 
142
- ### Публикация в npm
170
+ Витрина устроена как конструктор DevCloud: слева компонент и его код, справа панель свойств той же ширины, что в облаке. Если подпись не влезает, это видно сразу.
171
+
172
+ Внутри библиотеки импорты относительные. Витрина импортирует библиотеку через `#lib` (поле `imports` в `package.json`).
173
+
174
+ ## Выпуск
175
+
176
+ Выпуск запускается сообщением коммита в `main`:
177
+
178
+ - `[publish]` публикует пакет в npm;
179
+ - `[deploy]` обновляет витрину на GitHub Pages.
143
180
 
144
- Коммит в `main` с `[publish]` в сообщении (`"X.Y.Z [deploy] [publish]"`, версия поднята в `package.json`) запускает `.github/workflows/npm_publish.yaml`. Публикация идёт через **trusted publisher** npm (OIDC): workflow получает одноразовый токен от GitHub (`permissions: id-token: write`), постоянный `NPM_TOKEN` не нужен, provenance добавляется автоматически. Требования npm: npm CLI 11.5.1+ (workflow обновляет его сам), Node 22.14+, `repository.url` в `package.json` дословно совпадает с репозиторием.
181
+ Перед выпуском поднимите версию в `package.json`. Версия на витрине берётся оттуда же.
145
182
 
146
- Связь настраивается на npmjs.com → пакет → Settings → Trusted Publisher: GitHub Actions, `Oleg-Perevyshin/ElementsUI`, workflow `npm_publish.yaml`, разрешение «npm publish». Новая связь подтверждается первой успешной публикацией и должна пройти её в течение 2 дней, иначе истекает. Существующую связь изменить нельзя — только удалить и создать заново.
183
+ Публикация идёт через trusted publisher npm, постоянный токен не нужен. Связь настроена на npmjs.com в настройках пакета: GitHub Actions, репозиторий `Oleg-Perevyshin/ElementsUI`, workflow `npm_publish.yaml`.
147
184
 
148
- **Обновление DevCloud — автоматически.** После публикации job `update-devcloud` того же workflow ждёт новую версию в npm, клонирует `xPOE-Studio/DevCloud` (Forgejo) по секрету `DEVCLOUD_ACCESS_TOKEN` (токен Forgejo с правом записи в репозиторий), ставит `poe-svelte-ui-lib@<версия>`, прогоняет `svelte-kit sync`, `prisma generate` (с заглушкой `DATABASE_URL`, к БД не подключается) и `svelte-check` и, если проверка прошла, пушит в `main` коммит «Автообновление poe-svelte-ui-lib до <версия> — переразвёртывание облака [deploy]» с пояснением, что он создан автоматически при выпуске библиотеки, — облако разворачивается само. Вручную версию в облаке не поднимаем; изменения кода облака, которым нужна новая версия библиотеки, коммитятся без `[deploy]` до выпуска — их развернёт этот коммит. Если `svelte-check` упал, коммита нет, облако остаётся на прежней версии (смотрите лог job в GitHub Actions).
185
+ После публикации облако обновляется само. Workflow ставит новую версию в DevCloud, проверяет типы и, если всё прошло, поднимает вторую цифру версии облака и пушит туда коммит вида `1.6 [deploy] Обновление ElementsUI до 1.84.0`. Вручную версию библиотеки в облаке не поднимают. Если проверка упала, облако остаётся на старой версии, причину ищите в логе job `update-devcloud`.
149
186
 
150
187
  ---
151
188
 
152
- Лицензия: MIT — см. `LICENSE`.
189
+ Лицензия MIT, см. `LICENSE`.
@@ -1,5 +1,4 @@
1
- <!-- $lib/Accordion/Accordion.svelte — заголовок не увеличивается при раскрытии, радиус 14.
2
- Мастер-цвет (componentClass) — как у смарт-виджетов: иконка и текст заголовка цветом, фон заголовка — его мягким оттенком. -->
1
+ <!-- $lib/Accordion/Accordion.svelte — заголовок не увеличивается при раскрытии, радиус 14. Мастер-цвет (componentClass) — как у смарт-виджетов: иконка и текст заголовка цветом, фон заголовка — его мягким оттенком. -->
3
2
  <script lang="ts">
4
3
  import { slide } from "svelte/transition"
5
4
  import type { IAccordionProps } from "../types"
@@ -27,8 +26,7 @@
27
26
  transition:slide={{ duration: 200 }}
28
27
  >
29
28
  <div class="overflow-hidden rounded-[14px] border border-(--hairline-color) bg-(--back-color)">
30
- <!-- Фон заголовка — мягкий оттенок мастер-цвета (светлый в светлой теме, тёмный в тёмной), текст — мастер-цвет с цветом шрифта 60/40,
31
- раскрытое содержимое остаётся на чистом фоне (--back-color). -->
29
+ <!-- Фон заголовка — мягкий оттенок мастер-цвета (светлый в светлой теме, тёмный в тёмной), текст — мастер-цвет с цветом шрифта 60/40, раскрытое содержимое остаётся на чистом фоне (--back-color). -->
32
30
  <button
33
31
  class="flex w-full cursor-pointer items-center justify-between gap-3 bg-(--accent-soft) px-4 py-3 text-left text-[color-mix(in_srgb,var(--accent-color)_60%,var(--font-color))] transition-colors duration-150 hover:bg-[color-mix(in_srgb,var(--accent-color)_12%,var(--accent-soft))]"
34
32
  onclick={toggle}
@@ -1,148 +1,54 @@
1
- # Accordion Component
1
+ # Accordion
2
+
3
+ Сворачиваемый блок. В нём группируют компоненты, которые нужны не всегда: настройки, диагностику, редкие разделы.
2
4
 
3
5
  ## Назначение
4
6
 
5
- Сворачиваемый блок для группировки компонентов: настройки, диагностика, редко используемые разделы.
7
+ Сворачиваемый блок для группировки компонентов.
6
8
 
7
9
  ## Пакет данных
8
10
 
9
- Не связан с устройством — сам ничего не читает и не отправляет.
11
+ С устройством не связан, ничего не читает и не отправляет.
10
12
 
11
13
  ## Особенности
12
14
 
13
- - Перетащите компоненты внутрь — у аккордеона своя сетка, её размер задаётся при создании и ресайзе
14
- - Заголовок с иконкой открывает и закрывает содержимое
15
- - Мастер-цвет — как у смарт-виджетов (`widgetAccentStyle`): иконка, текст и стрелка заголовка — цветом из палитры, смешанным с цветом шрифта (читается в обеих темах), фон заголовка — его мягким оттенком (`--<цвет>-soft`: очень светлый в светлой теме, тёмный в тёмной); без выбора — акцент темы. Цвет из `label.class` перекрывает цвет текста
16
- - По высоте занимает одну строку сетки и растягивается по содержимому
17
-
18
- ### Адаптивность
19
-
20
- - Сетка содержимого адаптируется под размеры экрана (sm:p-3)
21
-
22
- ### Ограничения
23
-
24
- - При использовании изображения фона высота строк сетки устанавливается в `minmax(6.5rem, auto)` вместо `auto`
25
- - Необходимо убедиться, что переданный компонент иконки является валидным Svelte компонентом или SVG строкой
26
- - Размеры сетки должны быть положительными числами (по умолчанию 1x1)
27
-
28
- ### Производительность
29
-
30
- - Содержимое аккордеона рендерится только при его открытии (`{#if isOpen}`)
15
+ - В конструкторе компоненты перетаскивают внутрь аккордеона. У него своя сетка, её размер задаётся при создании и меняется растягиванием.
16
+ - Заголовок с иконкой открывает и закрывает содержимое.
17
+ - Мастер-цвет работает как у смарт-виджетов: иконка, текст и стрелка заголовка окрашены цветом из палитры, фон заголовка его мягким оттенком. Без цвета используется акцент темы. Цвет из `label.class` перекрывает цвет текста.
18
+ - Закрытый аккордеон занимает одну строку сетки, открытый растягивается по содержимому.
19
+ - Содержимое рисуется, только когда аккордеон открыт.
20
+ - С картинкой фона (`image`) строки сетки не ниже `6.5rem`.
31
21
 
32
22
  ## Пропсы
33
23
 
34
- | Название | Тип | По умолчанию | Описание |
35
- | ---------------- | ------------------------------------------------------ | --------------------- | ---------------------------------------------------------------------------------------- |
36
- | `id` | `string` | `crypto.randomUUID()` | Уникальный идентификатор компонента |
37
- | `isOpen` | `boolean` | `false` | Состояние открытия/закрытия; `$bindable` — `bind:isOpen` получает раскрытие по клику |
38
- | `wrapperClass` | `string` | `""` | Дополнительные CSS-классы для обертки компонента |
39
- | `componentClass` | `string` | `""` | Мастер-цвет: роль `bg-red`, `bg-green`... из палитры `COLOR_OPTIONS`; `""` — акцент темы |
40
- | `size` | `object` | `-` | Размеры сетки содержимого (количество колонок и строк) |
41
- | `size.height` | `number` | `1` | Количество строк в сетке содержимого |
42
- | `size.width` | `number` | `1` | Количество колонок в сетке содержимого |
43
- | `label` | `object` | `-` | Настройки заголовка аккордеона |
44
- | `label.name` | `string` | `""` | Текст заголовка аккордеона |
45
- | `label.class` | `string` | `"text-left"` | CSS-классы для стилизации текста заголовка |
46
- | `label.icon` | `ConstructorOfATypedSvelteComponent \| string \| null` | `null` | Иконка, отображаемая в заголовке (SVG строка или компонент) |
47
- | `children` | `Snippet` | `undefined` | Слот для содержимого, которое будет отображаться при открытии |
48
- | `image` | `string` | `""` | URL изображения для фона содержимого аккордеона |
49
-
50
- ### Колбэки
51
-
52
- Компонент не генерирует специфические события, но использует встроенную функцию `toggle()` для переключения состояния открытия/закрытия при клике на кнопку заголовка.
24
+ | Название | Тип | По умолчанию | Описание |
25
+ |---|---|---|---|
26
+ | `id` | `string` | `crypto.randomUUID()` | Идентификатор |
27
+ | `isOpen` | `boolean` | `false` | Открыт ли. Можно связать через `bind:isOpen` |
28
+ | `wrapperClass` | `string` | `""` | Классы обёртки |
29
+ | `componentClass` | `string` | `""` | Мастер-цвет: `bg-red`, `bg-green` и другие из `COLOR_OPTIONS`. Пусто — акцент темы |
30
+ | `size` | `{ width, height }` | `1 × 1` | Сетка содержимого: колонки и строки |
31
+ | `label.name` | `string` | `""` | Заголовок |
32
+ | `label.class` | `string` | `"text-left"` | Классы текста заголовка |
33
+ | `label.icon` | `Component \| string \| null` | `null` | Иконка заголовка |
34
+ | `image` | `string` | `""` | Картинка фона содержимого |
35
+ | `children` | `Snippet` | | Содержимое |
53
36
 
54
- ## Примеры
55
-
56
- ### Базовое использование
57
-
58
- ```svelte
59
- <script>
60
- import * as UI from "poe-svelte-ui-lib"
61
- </script>
62
-
63
- <UI.Accordion label={{ name: "Accordion" }} isOpen={true}>
64
- <div class="flex flex-col">
65
- <h1>Содержимое компонента</h1>
66
- <h1>Содержимое компонента</h1>
67
- <h1>Содержимое компонента</h1>
68
- </div>
69
- </UI.Accordion>
70
- ```
37
+ Колбэков нет. Открытие и закрытие компонент обрабатывает сам.
71
38
 
72
- ### Вложенные аккордеоны
39
+ ## Пример
73
40
 
74
41
  ```svelte
75
42
  <script>
76
43
  import * as UI from "poe-svelte-ui-lib"
44
+ let open = $state(false)
77
45
  </script>
78
46
 
79
- <UI.Accordion label={{ name: "Main Accordion" }} isOpen={true}>
80
- <UI.Accordion label={{ name: "Nested Accordion 1", class: "" }} isOpen={false} wrapperClass="col-span-3">
81
- <h6>Содержимое вложенного Accordion 1</h6>
82
- <h5>Содержимое вложенного Accordion 1</h5>
83
- <h4>Содержимое вложенного Accordion 1</h4>
84
- <h3>Содержимое вложенного Accordion 1</h3>
85
- <h2>Содержимое вложенного Accordion 1</h2>
86
- <h1>Содержимое вложенного Accordion 1</h1>
87
- </UI.Accordion>
88
- <UI.Accordion label={{ name: "Nested Accordion 2", class: "" }} isOpen={false} wrapperClass="col-span-3">
89
- <h1>Содержимое вложенного Accordion 2</h1>
90
- <h2>Содержимое вложенного Accordion 2</h2>
91
- <h3>Содержимое вложенного Accordion 2</h3>
92
- <h4>Содержимое вложенного Accordion 2</h4>
93
- <h5>Содержимое вложенного Accordion 2</h5>
94
- </UI.Accordion>
95
- <UI.Accordion label={{ name: "Nested Accordion 3", class: "" }} isOpen={false} wrapperClass="col-span-3">
96
- <h4>Содержимое вложенного Accordion 3</h4>
97
- <h3>Содержимое вложенного Accordion 3</h3>
98
- <h2>Содержимое вложенного Accordion 3</h2>
99
- <h1>Содержимое вложенного Accordion 3</h1>
100
- </UI.Accordion>
47
+ <UI.Accordion label={{ name: "Сеть" }} componentClass="bg-blue" bind:isOpen={open}>
48
+ <UI.Input label={{ name: "SSID" }} />
101
49
  </UI.Accordion>
102
50
  ```
103
51
 
104
- ## Конструктор свойств (AccordionProps.svelte)
105
-
106
- ### Описание
107
-
108
- Компонент `AccordionProps.svelte` предоставляет визуальный интерфейс для редактирования свойств аккордеона. Поддерживает два режима отображения: для конструктора и для редактирования.
109
-
110
- ### Пропсы конструктора
111
-
112
- | Название | Тип | По умолчанию | Описание |
113
- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------- | ------------ | ------------------------------------------------------- |
114
- | `component` | `UIComponent & { properties: Partial<IAccordionProps> }` | `-` | Объект компонента с его свойствами |
115
- | `onPropertyChange` | `(updates: Partial<{ properties?: string \| object; name?: string; access?: string; eventHandler?: IUIComponentHandler }>) => void` | `-` | Коллбэк для обновления свойств компонента |
116
- | `forConstructor` | `boolean` | `true` | Режим отображения (для конструктора или редактирования) |
117
-
118
- ### Особенности конструктора
119
-
120
- - Включает модальное окно для выбора иконок из библиотеки
121
- - Поддерживает загрузку изображений для фона
122
- - Поддерживает валидацию числовых значений (min/max) для размеров
123
-
124
- ### Что настраивается
125
-
126
- - Заголовок, иконка, мастер-цвет заголовка, «Открыт по умолчанию» — состояние при загрузке интерфейса
127
- - Картинка фона — изображение под содержимым (например схема устройства), поверх неё располагаются компоненты
128
-
129
- ## Внутреннее устройство
130
-
131
- ### Реактивность
132
-
133
- - Переменная `isOpen` является реактивной и управляет состоянием отображения содержимого
134
- - Функция `toggle()` изменяет состояние `isOpen`, вызывая повторный рендеринг компонента
135
-
136
- ### Сторы и зависимости
137
-
138
- - Применяется переход `slide` из `svelte/transition` для анимации открытия/закрытия
139
-
140
- ### Директивы
141
-
142
- - `transition:slide` для анимации открытия/закрытия содержимого
143
- - `@render children` для отображения переданного содержимого
144
- - `bind:isOpen` в конструкторе свойств для двусторонней привязки состояния
145
-
146
- ### Слоты
52
+ ## Панель свойств (AccordionProps.svelte)
147
53
 
148
- - `children` - слот для содержимого, которое отображается внутри аккордеона при его открытии
54
+ В конструкторе задают заголовок, иконку, мастер-цвет, картинку фона и размер сетки.
@@ -1,12 +1,4 @@
1
- <!-- $lib/Button/Button.svelte — шаг 3 плана.
2
- API не изменён: id, wrapperClass, componentClass, disabled, content, keyBind, onClick.
3
- Что изменилось внутри:
4
- • роль определяется значением bg-* (намерение), а не фактом его наличия;
5
- • убрано автоподчёркивание текста — кнопка больше не выглядит ссылкой;
6
- • единый радиус 10px (иконка без подписи — круг), высота 32px (стандарт полей h-8), кегль 14/600;
7
- • кольцо фокуса вместо размытой тени;
8
- • disabled через токены, а не opacity: 0.5;
9
- • иконка встала в поток (flex + gap) вместо absolute left-3. -->
1
+ <!-- $lib/Button/Button.svelte — кнопка: роль по значению bg-*, радиус 10px (иконка без подписи — круг), высота 32px, кольцо фокуса, иконка в потоке через flex + gap -->
10
2
  <script lang="ts">
11
3
  import { onMount } from "svelte"
12
4
  import type { IButtonProps } from "../types"
@@ -29,11 +21,7 @@
29
21
 
30
22
  let showInfo = $state(false)
31
23
 
32
- /* ─── Роль кнопки по последнему классу bg-* ─────────────────────────
33
- bg-blue / bg-green / bg-cyan / bg-purple / bg-orange / bg-yellow → primary (заливка + белый текст)
34
- bg-red / bg-pink → destructive
35
- bg-max / bg-gray / bg-*-soft → secondary (поверхность + контур)
36
- bg-transparent / без bg-* → plain (текст акцентом) */
24
+ /* ─── Роль кнопки по последнему классу bg-* ───────────────────────── bg-blue / bg-green / bg-cyan / bg-purple / bg-orange / bg-yellow → primary (заливка + белый текст) bg-red / bg-pink → destructive bg-max / bg-gray / bg-*-soft → secondary (поверхность + контур) bg-transparent / без bg-* → plain (текст акцентом) */
37
25
  const SURFACE_BG = ["bg-max", "bg-gray"]
38
26
  const DANGER_BG = ["bg-red", "bg-pink"]
39
27
 
@@ -51,10 +39,7 @@
51
39
 
52
40
  const isIconOnly = $derived(!!content?.icon && !content.name?.trim())
53
41
 
54
- /* bg-(--bg-color) намеренно не входит в roleClass: он приклеивается к готовому
55
- className вне twMerge (см. разметку ниже) — иначе twMerge видит его и явный
56
- bg-* из componentClass (bg-red, bg-max…) как конфликтующие утилиты одной
57
- группы и вырезает один из них, из-за чего заливка кнопки пропадает. */
42
+ /* bg-(--bg-color) намеренно не входит в roleClass: он приклеивается к готовому className вне twMerge (см. разметку ниже) — иначе twMerge видит его и явный bg-* из componentClass (bg-red, bg-max…) как конфликтующие утилиты одной группы и вырезает один из них, из-за чего заливка кнопки пропадает. */
58
43
  const roleBg = $derived.by(() => {
59
44
  if (disabled) return "bg-(--gray-color)"
60
45
  if (role === "plain") return "bg-transparent"