poe-svelte-ui-lib 1.28.4 → 1.28.6

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.
@@ -3,7 +3,7 @@
3
3
  import { T } from "../locales/i18n"
4
4
  import { type UIComponent, type IButtonProps, type IOption, updateProperty, type IUIComponentHandler } from "../types"
5
5
  import * as UI from ".."
6
- import { optionsStore } from "../options"
6
+ import { optionsStore, findColorOption } from "../options"
7
7
  import { twMerge } from "tailwind-merge"
8
8
  import { ICONS } from "../icons"
9
9
  import CommonSnippets from "../CommonSnippets.svelte"
@@ -31,11 +31,7 @@
31
31
  $optionsStore.HEADER_OPTIONS.find((h) => h.value === component.eventHandler.Header) ?? { id: "", name: "", value: "", class: "!w-1/4" },
32
32
  )
33
33
 
34
- const initialColor = $derived(
35
- $optionsStore.COLOR_OPTIONS.find((c) =>
36
- (c.value as string).includes(component.properties.componentClass?.split(" ").find((cls: string) => cls.startsWith("bg-"))),
37
- ),
38
- )
34
+ const initialColor = $derived(findColorOption($optionsStore.COLOR_OPTIONS, component.properties.componentClass))
39
35
 
40
36
  const initialHeight = $derived(
41
37
  $optionsStore.HEIGHT_OPTIONS.find((h) =>
@@ -1,4 +1,8 @@
1
- <script lang="ts" module>
1
+ <script lang="ts">
2
+ import { tick } from "svelte"
3
+ import MoveVerticalIcon from "./libIcons/MoveVerticalIcon.svelte"
4
+ import { twMerge } from "tailwind-merge"
5
+
2
6
  let dragState = $state({
3
7
  isDragging: false,
4
8
  element: null as any,
@@ -13,12 +17,6 @@
13
17
  })
14
18
 
15
19
  let commandItems: Element[] = $state([])
16
- </script>
17
-
18
- <script lang="ts">
19
- import { tick } from "svelte"
20
- import MoveVerticalIcon from "./libIcons/MoveVerticalIcon.svelte"
21
- import { twMerge } from "tailwind-merge"
22
20
 
23
21
  let {
24
22
  wrapperClass,
@@ -41,7 +39,7 @@
41
39
  /* Перетаскивание с MouseEvent */
42
40
  const startDrag = async (e: MouseEvent) => {
43
41
  const movedElement = document.querySelector(
44
- containerIndex == null ? `#${elementsId}-${elementIndex}` : `#${elementsId}-${elementIndex}-${dragState.containerIndex || containerIndex}`,
42
+ containerIndex == null ? `#${elementsId}-${elementIndex}` : `#${elementsId}-${elementIndex}-${containerIndex}`,
45
43
  ) as HTMLElement
46
44
 
47
45
  if (!movedElement) return
@@ -1,4 +1,4 @@
1
- <!-- $lib/Input/Input.svelte — радиус 10, высота 36, выравнивание по левому краю,
1
+ <!-- $lib/Input/Input.svelte — радиус 10, высота 32 (h-8), выравнивание по левому краю,
2
2
  кольцо фокуса вместо размытой тени. Вся логика (regExp, roundToClean,
3
3
  handleInputChange, счётчик, копирование) не тронута. -->
4
4
  <script lang="ts">
@@ -39,13 +39,17 @@
39
39
 
40
40
  $effect(() => {
41
41
  if (help.regExp && type !== "number") isValid = RegExpObj().test(typeof value === "string" ? value : String(value))
42
+ else isValid = true
42
43
  })
43
44
 
44
45
  const handleInputChange = (value: string | number) => {
45
46
  if (type === "number") {
46
- const numValue = typeof value === "string" ? parseFloat(value.replace(",", ".")) : Number(value)
47
- if (!isNaN(numValue)) onUpdate?.(numValue)
48
- else onUpdate?.(value as string)
47
+ let numValue = typeof value === "string" ? parseFloat(value.replace(",", ".")) : Number(value)
48
+ if (!isNaN(numValue)) {
49
+ if (typeof number?.minNum === "number") numValue = Math.max(numValue, number.minNum)
50
+ if (typeof number?.maxNum === "number") numValue = Math.min(numValue, number.maxNum)
51
+ onUpdate?.(numValue)
52
+ } else onUpdate?.(value as string)
49
53
  } else {
50
54
  onUpdate?.(value as string)
51
55
  }
@@ -3,7 +3,7 @@
3
3
  import { T } from "../locales/i18n"
4
4
  import type { IInputProps, UIComponent, IOption, IUIComponentHandler } from "../types"
5
5
  import * as UI from ".."
6
- import { optionsStore } from "../options"
6
+ import { optionsStore, findColorOption } from "../options"
7
7
  import { twMerge } from "tailwind-merge"
8
8
  import Library from "../libIcons/Library.svelte"
9
9
  import CommonSnippets from "../CommonSnippets.svelte"
@@ -24,11 +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
- const initialColor = $derived(
28
- $optionsStore.COLOR_OPTIONS.find((c) =>
29
- (c.value as string).includes(component.properties.componentClass?.split(" ").find((cls: string) => cls.startsWith("bg-"))),
30
- ),
31
- )
27
+ const initialColor = $derived(findColorOption($optionsStore.COLOR_OPTIONS, component.properties.componentClass))
32
28
 
33
29
  const initialAlign = $derived(
34
30
  $optionsStore.TEXT_ALIGN_OPTIONS.find((a) =>
@@ -1,10 +1,10 @@
1
1
  <script lang="ts">
2
2
  import { getContext } from "svelte"
3
3
  import { T } from "../locales/i18n"
4
- import { type UIComponent, type IGraphProps, updateProperty, type IOption, type IUIComponentHandler } from "../types"
4
+ import { type UIComponent, type IJoystickProps, updateProperty, type IUIComponentHandler } from "../types"
5
5
  import * as UI from ".."
6
6
  import { ICONS } from "../icons"
7
- import { optionsStore } from "../options"
7
+ import { optionsStore, findColorOption } from "../options"
8
8
  import CommonSnippets from "../CommonSnippets.svelte"
9
9
  import PropsGroup from "../PropsGroup.svelte"
10
10
 
@@ -13,7 +13,7 @@
13
13
  onPropertyChange,
14
14
  forConstructor = true,
15
15
  } = $props<{
16
- component: UIComponent & { properties: Partial<IGraphProps> }
16
+ component: UIComponent & { properties: Partial<IJoystickProps> }
17
17
  onPropertyChange: (updates: Partial<{ properties?: string | object; name?: string; access?: string; eventHandler?: IUIComponentHandler }>) => void
18
18
  forConstructor?: boolean
19
19
  }>()
@@ -27,11 +27,7 @@
27
27
  ),
28
28
  )
29
29
 
30
- const initialColor = $derived(
31
- $optionsStore.COLOR_OPTIONS.find((c) =>
32
- (c.value as string).includes(component.properties.wrapperClass?.split(" ").find((cls: string) => cls.startsWith("bg-"))),
33
- ),
34
- )
30
+ const initialColor = $derived(findColorOption($optionsStore.COLOR_OPTIONS, component.properties.wrapperClass))
35
31
  </script>
36
32
 
37
33
  {#snippet JoystickAxesMinMax()}
@@ -1,7 +1,7 @@
1
- import { type UIComponent, type IGraphProps, type IUIComponentHandler } from "../types";
1
+ import { type UIComponent, type IJoystickProps, type IUIComponentHandler } from "../types";
2
2
  type $$ComponentProps = {
3
3
  component: UIComponent & {
4
- properties: Partial<IGraphProps>;
4
+ properties: Partial<IJoystickProps>;
5
5
  };
6
6
  onPropertyChange: (updates: Partial<{
7
7
  properties?: string | object;
@@ -19,15 +19,18 @@
19
19
  /* Мастер-цвет (тот же bg-* из optionsStore.COLOR_OPTIONS, что и у остальных примитивов) —
20
20
  красить саму карту цветом смысла нет (это базовая карта MapLibre), поэтому проявляется на
21
21
  ФОНЕ наших собственных оверлеев поверх неё: панели управления (CustomControl) и карточки
22
- устройства (Popup) — см. roleBgClass ниже, применяется прямо в разметке. */
22
+ устройства (Popup) — см. roleBgClass/roleBgPaint ниже, применяются прямо в разметке. */
23
23
  const roleBgClass = $derived.by(() => {
24
24
  const role = wrapperClass.match(/bg-(\w+)/)?.[1]
25
- /* bg-(--bg-color) — реальная utility, красящая заливку; bg-{role} лишь задаёт переменную
26
- --bg-color (см. app.css), тот же приём, что и в Button.svelte (roleBg/roleClass).
27
- text-(--on-accent) — иначе тёмный текст (задуман под белую подложку control'ов MapLibre
28
- по умолчанию) нечитаем на цветной заливке. */
29
- return role && role !== "max" ? `bg-(--bg-color) bg-${role} text-(--on-accent)` : ""
25
+ /* bg-{role} лишь задаёт переменную --bg-color (см. app.css); text-(--on-accent) — иначе
26
+ тёмный текст (задуман под белую подложку control'ов MapLibre по умолчанию) нечитаем на
27
+ цветной заливке. Красящая bg-(--bg-color) — НЕ здесь, см. roleBgPaint: если оставить обе
28
+ bg-* утилиты в одной строке, twMerge видит конфликт одной группы и вырезает одну из них
29
+ (та же ловушка, что и в Button.svelte, см. его комментарий про roleBg/roleClass). */
30
+ return role && role !== "max" ? `bg-${role} text-(--on-accent)` : ""
30
31
  })
32
+ /* Приклеивается к className СНАРУЖИ twMerge — иначе конфликтует с bg-{role} внутри roleBgClass. */
33
+ const roleBgPaint = $derived(roleBgClass ? "bg-(--bg-color)" : "")
31
34
 
32
35
  /* Акцентное кольцо вокруг самой карты. Намеренно ring, а не border: border меняет content-box
33
36
  контейнера MapLibre уже ПОСЛЕ монтажа, а сама MapLibre не переотрисовывает canvas при таком
@@ -172,7 +175,7 @@
172
175
  <FullScreenControl />
173
176
 
174
177
  <CustomControl position="top-left">
175
- <div class={twMerge("flex flex-wrap items-center gap-3 rounded-lg px-2 py-1 text-black", roleBgClass)}>
178
+ <div class={`${twMerge("flex flex-wrap items-center gap-3 rounded-lg px-2 py-1 text-black", roleBgClass)} ${roleBgPaint}`}>
176
179
  <label class="flex items-center gap-1.5 text-sm font-medium">
177
180
  <input type="checkbox" bind:checked={trackEnabled} />
178
181
  {$T("constructor.props.map.track")}
@@ -255,7 +258,9 @@
255
258
  <h6 class="text-sm leading-none font-bold">{device.DevName}</h6>
256
259
  </div>
257
260
 
258
- <div class={twMerge("grid grid-cols-2 gap-x-3 gap-y-1 rounded-lg bg-(--container-color) p-2 text-xs", roleBgClass)}>
261
+ <div
262
+ class={`${twMerge("grid grid-cols-2 gap-x-3 gap-y-1 rounded-lg bg-(--container-color) p-2 text-xs", roleBgClass)} ${roleBgPaint}`}
263
+ >
259
264
  <div>
260
265
  <p class="text-[0.6rem] font-semibold tracking-wide uppercase opacity-60">Lat / Lon</p>
261
266
  <p class="font-medium">{device.NavLat.toFixed(5)}, {device.NavLon.toFixed(5)}</p>
@@ -2,7 +2,7 @@
2
2
  import { T } from "../locales/i18n"
3
3
  import { type UIComponent, type IMapProps, updateProperty, type IUIComponentHandler } from "../types"
4
4
  import { ICONS } from "../icons"
5
- import { optionsStore } from "../options"
5
+ import { optionsStore, findColorOption } from "../options"
6
6
  import { getContext } from "svelte"
7
7
  import CommonSnippets from "../CommonSnippets.svelte"
8
8
  import PropsGroup from "../PropsGroup.svelte"
@@ -30,9 +30,7 @@
30
30
  )
31
31
 
32
32
  const initialColor = $derived(
33
- $optionsStore.COLOR_OPTIONS.find((c) =>
34
- (c.value as string).includes(component.properties.wrapperClass?.split(" ").find((cls: string) => cls.startsWith("bg-"))),
35
- ),
33
+ findColorOption($optionsStore.COLOR_OPTIONS, component.properties.wrapperClass),
36
34
  )
37
35
  </script>
38
36
 
package/dist/Modal.svelte CHANGED
@@ -40,6 +40,7 @@
40
40
  $effect(() => {
41
41
  if (isOpen) ModalStack.open(modalId)
42
42
  else ModalStack.close(modalId)
43
+ return () => ModalStack.close(modalId)
43
44
  })
44
45
 
45
46
  $effect(() => {
@@ -3,7 +3,7 @@
3
3
  import { T } from "../locales/i18n"
4
4
  import { updateProperty, type IOption, type IPeriodChartLevel, type IPeriodChartProps, type IUIComponentHandler, type UIComponent } from "../types"
5
5
  import * as UI from ".."
6
- import { optionsStore } from "../options"
6
+ import { optionsStore, findColorOption } from "../options"
7
7
  import ButtonAdd from "../libIcons/ButtonAdd.svelte"
8
8
  import ButtonDelete from "../libIcons/ButtonDelete.svelte"
9
9
  import CommonSnippets from "../CommonSnippets.svelte"
@@ -24,11 +24,7 @@
24
24
 
25
25
  let itemsContainer: HTMLDivElement | null = $state(null)
26
26
 
27
- const initialColor = $derived(
28
- $optionsStore.COLOR_OPTIONS.find((c) =>
29
- (c.value as string).includes(component.properties.wrapperClass?.split(" ").find((cls: string) => cls.startsWith("bg-"))),
30
- ),
31
- )
27
+ const initialColor = $derived(findColorOption($optionsStore.COLOR_OPTIONS, component.properties.wrapperClass))
32
28
 
33
29
  /* levels[].data/labels хранятся как number[]/string[], редактируются одной строкой через запятую (fallback для литеральных демо-данных) */
34
30
  const parseNumbers = (text: string): number[] =>
@@ -3,7 +3,7 @@
3
3
  import { T } from "../locales/i18n"
4
4
  import { type UIComponent, type IProgressBarProps, updateProperty, type IUIComponentHandler } from "../types"
5
5
  import * as UI from ".."
6
- import { optionsStore } from "../options"
6
+ import { optionsStore, findColorOption } from "../options"
7
7
  import CommonSnippets from "../CommonSnippets.svelte"
8
8
  import PropsGroup from "../PropsGroup.svelte"
9
9
  import PropsListModal from "../PropsListModal.svelte"
@@ -104,9 +104,7 @@
104
104
  wrapperClass="min-w-56 flex-[2]"
105
105
  type="buttons"
106
106
  options={$optionsStore.COLOR_OPTIONS.filter((option) => option.value !== "bg-max")}
107
- value={$optionsStore.COLOR_OPTIONS.find((c) =>
108
- (c.value as string).includes(progress.class.split(" ").find((cls: string) => cls.startsWith("bg-"))),
109
- )}
107
+ value={findColorOption($optionsStore.COLOR_OPTIONS, progress.class)}
110
108
  onUpdate={(value) => {
111
109
  const progresses = [...(component.properties?.items || [])]
112
110
  progresses[index]["class"] = (value as UI.IOption).value
@@ -102,10 +102,9 @@
102
102
  const selectOption = (option: IOption<T>, event: MouseEvent) => {
103
103
  event.stopPropagation()
104
104
 
105
- if (type === "buttons" && multiSelect && value) {
106
- if (!Array.isArray(value)) value = [value]
107
- if (value.find((v) => v.value === option.value)) value = value.filter((op) => op.value !== option.value)
108
- else value.push(option)
105
+ if (type === "buttons" && multiSelect) {
106
+ const current = Array.isArray(value) ? value : value ? [value] : []
107
+ value = current.find((v) => v.value === option.value) ? current.filter((op) => op.value !== option.value) : [...current, option]
109
108
  } else {
110
109
  value = option
111
110
  }
@@ -123,7 +122,9 @@
123
122
  id: `input-${Date.now()}`,
124
123
  name: searchValue,
125
124
  value:
126
- typeof options[0]?.value == "number" ? ((Number(searchValue) as T) == undefined ? (Number(searchValue) as T) : (searchValue as T)) : (searchValue as T),
125
+ typeof options[0]?.value == "number" && searchValue !== "" && !isNaN(Number(searchValue))
126
+ ? (Number(searchValue) as T)
127
+ : (searchValue as T),
127
128
  }
128
129
  value = selectedOption
129
130
  onUpdate?.(selectedOption)
@@ -256,6 +257,7 @@
256
257
  componentClass,
257
258
  )}
258
259
  id={`${id}-${crypto.randomUUID().slice(0, 6)}`}
260
+ autocomplete="off"
259
261
  {disabled}
260
262
  oninput={handleSearch}
261
263
  onclick={(e) => toggleDropdown(e)}
@@ -5,7 +5,7 @@
5
5
  import * as UI from ".."
6
6
  import ButtonDelete from "../libIcons/ButtonDelete.svelte"
7
7
  import ButtonAdd from "../libIcons/ButtonAdd.svelte"
8
- import { optionsStore } from "../options.js"
8
+ import { optionsStore, findColorOption } from "../options.js"
9
9
  import CommonSnippets from "../CommonSnippets.svelte"
10
10
  import PropsGroup from "../PropsGroup.svelte"
11
11
  import PropsListModal from "../PropsListModal.svelte"
@@ -235,9 +235,7 @@
235
235
  label={{ name: $T("constructor.props.colors") }}
236
236
  type="buttons"
237
237
  options={$optionsStore.COLOR_OPTIONS}
238
- value={$optionsStore.COLOR_OPTIONS.find((c) =>
239
- (c.value as string).includes(option.class.split(" ").find((cls: string) => cls.startsWith("bg-"))),
240
- )}
238
+ value={findColorOption($optionsStore.COLOR_OPTIONS, option.class)}
241
239
  onUpdate={(option) => {
242
240
  const options = [...(component.properties?.options || [])]
243
241
  options[index]["class"] = (option as UI.IOption).value
@@ -3,7 +3,7 @@
3
3
  import { T } from "../locales/i18n"
4
4
  import { type UIComponent, type ISliderProps, updateProperty, type IUIComponentHandler } from "../types"
5
5
  import * as UI from ".."
6
- import { optionsStore } from "../options"
6
+ import { optionsStore, findColorOption } from "../options"
7
7
  import CommonSnippets from "../CommonSnippets.svelte"
8
8
  import PropsGroup from "../PropsGroup.svelte"
9
9
 
@@ -26,11 +26,7 @@
26
26
  ),
27
27
  )
28
28
 
29
- const initialColor = $derived(
30
- $optionsStore.COLOR_OPTIONS.find((c) =>
31
- (c.value as string).includes(component.properties.wrapperClass?.split(" ").find((cls: string) => cls.startsWith("bg-"))),
32
- ),
33
- )
29
+ const initialColor = $derived(findColorOption($optionsStore.COLOR_OPTIONS, component.properties.wrapperClass))
34
30
  </script>
35
31
 
36
32
  {#snippet SliderType()}
@@ -3,7 +3,7 @@
3
3
  import { T } from "../locales/i18n"
4
4
  import { type UIComponent, type ISwitchProps, updateProperty, type IOption, type IUIComponentHandler } from "../types"
5
5
  import * as UI from ".."
6
- import { optionsStore } from "../options"
6
+ import { optionsStore, findColorOption } from "../options"
7
7
  import ButtonDelete from "../libIcons/ButtonDelete.svelte"
8
8
  import ButtonAdd from "../libIcons/ButtonAdd.svelte"
9
9
  import CommonSnippets from "../CommonSnippets.svelte"
@@ -21,9 +21,7 @@
21
21
  }>()
22
22
  const DeviceVariables = getContext<{ id: string; value: string; name: string }[]>("DeviceVariables")
23
23
  let VARIABLE_OPTIONS = $derived(DeviceVariables && Array.isArray(DeviceVariables) ? DeviceVariables : [])
24
- let initialColor = $optionsStore.COLOR_OPTIONS.find((c) =>
25
- (c.value as string).includes(component.properties.options[0].class.split(" ").find((cls: string) => cls.startsWith("bg-"))),
26
- )
24
+ let initialColor = $derived(findColorOption($optionsStore.COLOR_OPTIONS, component.properties.options[0].class))
27
25
  const initialAlign = $derived(
28
26
  $optionsStore.TEXT_ALIGN_OPTIONS.find((a) =>
29
27
  (a.value as string).includes(component.properties.label?.class?.split(" ").find((cls: string) => cls.startsWith("text-"))),
@@ -139,9 +137,7 @@
139
137
  label={{ name: $T("constructor.props.colors") }}
140
138
  type="buttons"
141
139
  options={$optionsStore.COLOR_OPTIONS.filter((option) => option.value !== "bg-max" && option.value !== "bg-gray")}
142
- value={$optionsStore.COLOR_OPTIONS.find((c) =>
143
- (c.value as string).includes(option.class.split(" ").find((cls: string) => cls.startsWith("bg-"))),
144
- )}
140
+ value={findColorOption($optionsStore.COLOR_OPTIONS, option.class)}
145
141
  onUpdate={(option) => {
146
142
  const options = [...(component.properties?.options || [])]
147
143
  options[index]["class"] = (option as UI.IOption).value
@@ -105,7 +105,7 @@
105
105
  if (button.onClick) button.onClick(row)
106
106
  else if (button.eventHandler && onClick) {
107
107
  let value: Record<string, boolean | string | number | number[] | object | null> = {}
108
- button.eventHandler.Variables.forEach((v: string) => {
108
+ ;(button.eventHandler.Variables ?? []).forEach((v: string) => {
109
109
  if (
110
110
  header.some(
111
111
  (h) =>
@@ -124,7 +124,7 @@
124
124
  const selectOption = async (index: number, key: any, selectIndex: number, option: IOption<string | number>, event: MouseEvent) => {
125
125
  event.stopPropagation()
126
126
 
127
- let existingItem = body[index][key]
127
+ let existingItem = body[index][key.slice(0, -2)]
128
128
  isDropdownOpen = null
129
129
 
130
130
  setTimeout(() => {
@@ -163,7 +163,7 @@
163
163
 
164
164
  let min = progressBar?.minNum ?? 0
165
165
  let max = progressBar?.maxNum ?? 100
166
- if (value) return (((Math.min(Math.max(value, min), max) - min) / (max - min)) * 100) as number
166
+ if (value != null && !isNaN(value)) return (((Math.min(Math.max(value, min), max) - min) / (max - min)) * 100) as number
167
167
  }
168
168
 
169
169
  const roundToClean = (num: number): number => {
@@ -5,7 +5,7 @@
5
5
  import * as UI from ".."
6
6
  import ButtonDelete from "../libIcons/ButtonDelete.svelte"
7
7
  import ButtonAdd from "../libIcons/ButtonAdd.svelte"
8
- import { optionsStore } from "../options"
8
+ import { optionsStore, findColorOption } from "../options"
9
9
  import { ICONS } from "../icons"
10
10
  import CommonSnippets from "../CommonSnippets.svelte"
11
11
  import PropsGroup from "../PropsGroup.svelte"
@@ -29,11 +29,7 @@
29
29
 
30
30
  let isDropdownOpen = $state(-1)
31
31
 
32
- const initialColor = $derived(
33
- $optionsStore.COLOR_OPTIONS.find((c) =>
34
- (c.value as string).includes(component.properties.wrapperClass?.split(" ").find((cls: string) => cls.startsWith("bg-"))),
35
- ),
36
- )
32
+ const initialColor = $derived(findColorOption($optionsStore.COLOR_OPTIONS, component.properties.wrapperClass))
37
33
 
38
34
  const initialAlign = $derived(
39
35
  $optionsStore.TEXT_ALIGN_OPTIONS.find((a) =>
@@ -352,11 +348,7 @@
352
348
  label={{ name: $T("constructor.props.colors") }}
353
349
  type="buttons"
354
350
  options={$optionsStore.COLOR_OPTIONS.filter((option) => option.value !== "bg-max")}
355
- value={$optionsStore.COLOR_OPTIONS.find((c) =>
356
- (c.value as string).includes(
357
- (button.class ?? component.properties.wrapperClass).split(" ").find((cls: string) => cls.startsWith("bg-")),
358
- ),
359
- )}
351
+ value={findColorOption($optionsStore.COLOR_OPTIONS, button.class ?? component.properties.wrapperClass)}
360
352
  onUpdate={(option) => {
361
353
  if (button.class === (option as UI.IOption).value) updateContentProperty(columnIndex, index, "class", "bg-transparent")
362
354
  else updateContentProperty(columnIndex, index, "class", (option as UI.IOption).value)
@@ -2,7 +2,7 @@
2
2
  import { T } from "../locales/i18n"
3
3
  import { updateProperty, type IOption, type ITabsProps, type IUIComponentHandler, type UIComponent } from "../types"
4
4
  import * as UI from ".."
5
- import { optionsStore } from "../options"
5
+ import { optionsStore, findColorOption } from "../options"
6
6
  import { ICONS } from "../icons"
7
7
  import ButtonAdd from "../libIcons/ButtonAdd.svelte"
8
8
  import ButtonDelete from "../libIcons/ButtonDelete.svelte"
@@ -23,11 +23,7 @@
23
23
 
24
24
  let itemsContainer: HTMLDivElement | null = $state(null)
25
25
 
26
- const initialColor = $derived(
27
- $optionsStore.COLOR_OPTIONS.find((c) =>
28
- (c.value as string).includes(component.properties.wrapperClass?.split(" ").find((cls: string) => cls.startsWith("bg-"))),
29
- ),
30
- )
26
+ const initialColor = $derived(findColorOption($optionsStore.COLOR_OPTIONS, component.properties.wrapperClass))
31
27
 
32
28
  const initialPosition = $derived(
33
29
  $optionsStore.ICON_TEXT_POSITION_OPTIONS.find((c) =>
@@ -2,7 +2,7 @@
2
2
  import { T } from "../locales/i18n"
3
3
  import { updateProperty, type ITextFieldProps, type IUIComponentHandler, type UIComponent } from "../types"
4
4
  import * as UI from "../index"
5
- import { optionsStore } from "../options"
5
+ import { optionsStore, findColorOption } from "../options"
6
6
  import { getContext } from "svelte"
7
7
  import { twMerge } from "tailwind-merge"
8
8
  import CommonSnippets from "../CommonSnippets.svelte"
@@ -27,11 +27,7 @@
27
27
  (a.value as string).includes(component.properties.content?.class?.split(" ").find((cls: string) => cls.startsWith("text-"))),
28
28
  ),
29
29
  )
30
- const initialColor = $derived(
31
- $optionsStore.TEXT_COLOR_OPTIONS.find((c) =>
32
- (c.value as string).includes(component.properties.wrapperClass?.split(" ").find((cls: string) => cls.startsWith("text-"))),
33
- ),
34
- )
30
+ const initialColor = $derived(findColorOption($optionsStore.TEXT_COLOR_OPTIONS, component.properties.wrapperClass, "text-"))
35
31
  </script>
36
32
 
37
33
  {#snippet TextFieldSize()}
@@ -4,7 +4,7 @@
4
4
  import * as UI from ".."
5
5
  import CommonSnippets from "../CommonSnippets.svelte"
6
6
  import PropsGroup from "../PropsGroup.svelte"
7
- import { optionsStore } from "../options"
7
+ import { optionsStore, findColorOption } from "../options"
8
8
 
9
9
  const {
10
10
  component,
@@ -16,11 +16,7 @@
16
16
  forConstructor?: boolean
17
17
  }>()
18
18
 
19
- const initialColor = $derived(
20
- $optionsStore.COLOR_OPTIONS.find((c) =>
21
- (c.value as string).includes(component.properties.wrapperClass?.split(" ").find((cls: string) => cls.startsWith("bg-"))),
22
- ),
23
- )
19
+ const initialColor = $derived(findColorOption($optionsStore.COLOR_OPTIONS, component.properties.wrapperClass))
24
20
  </script>
25
21
 
26
22
  {#snippet VideoViewershowSelect()}
@@ -2,7 +2,7 @@
2
2
  import { T } from "../locales/i18n"
3
3
  import { updateProperty, type IUIComponentHandler, type UIComponent } from "../types"
4
4
  import * as UI from ".."
5
- import { optionsStore } from "../options"
5
+ import { optionsStore, findColorOption } from "../options"
6
6
  import { ICONS_ARRAY } from "../icons"
7
7
  import { twMerge } from "tailwind-merge"
8
8
  import CommonSnippets from "../CommonSnippets.svelte"
@@ -22,11 +22,7 @@
22
22
  const DeviceVariables = getContext<{ id: string; value: string; name: string }[]>("DeviceVariables")
23
23
  let VARIABLE_OPTIONS = $derived(DeviceVariables && Array.isArray(DeviceVariables) ? DeviceVariables : [])
24
24
 
25
- const initialColor = $derived(
26
- $optionsStore.COLOR_OPTIONS.find((c) =>
27
- (c.value as string).includes(component.properties.settings.class?.split(" ").find((cls: string) => cls.startsWith("bg-"))),
28
- ),
29
- )
25
+ const initialColor = $derived(findColorOption($optionsStore.COLOR_OPTIONS, component.properties.settings.class))
30
26
 
31
27
  /* Один мастер-цвет вместо двух независимых пикеров: цвет иконки больше не выбирается отдельно,
32
28
  а выводится из того же bg-* (COLOR_OPTIONS и TEXT_COLOR_OPTIONS — одна и та же ролевая палитра
@@ -34,8 +34,6 @@ const translations = {
34
34
  "constructor.props.align.center": ["Центр", "Center", "居中"],
35
35
  "constructor.props.align.right": ["Справа", "Right", "右"],
36
36
  "constructor.props.align.justify": ["Ширина", "Justify", "两端对齐"],
37
- "constructor.props.type.main": ["Основной", "Main", "主要"],
38
- "constructor.props.type.sub": ["Вложенный", "Nested", "嵌套"],
39
37
  "constructor.props.type.text": ["Текст", "Text", "文本"],
40
38
  "constructor.props.type.password": ["Пароль", "Password", "密码"],
41
39
  "constructor.props.type.number": ["Число", "Number", "数字"],
@@ -252,9 +250,6 @@ const translations = {
252
250
  "constructor.props.source": ["Источник", "Source", "来源"],
253
251
  "constructor.props.showSelect": ["Выбор источника", "Source selection", "来源选择"],
254
252
  "constructor.props.widget.mode": ["Зацикленный", "Looped", "循环"],
255
- "constructor.props.table.type": ["Тип таблицы", "Table type", "表格类型"],
256
- "constructor.props.table.type.table": ["Статическая", "Static", "静态表格"],
257
- "constructor.props.table.type.logger": ["Логи", "Logs", "日志表格"],
258
253
  "constructor.props.table.columns": ["Колонки таблицы", "Table columns", "表格列"],
259
254
  "constructor.props.table.text.key": ["Ключ текста", "Text key", "文本键"],
260
255
  "constructor.props.table.select.key": ["Ключ селектора", "Selector key", "选择器键"],
@@ -320,60 +315,19 @@ const translations = {
320
315
  "constructor.props.icon.battery": ["Аккумулятор", "Battery", "电池"],
321
316
  "constructor.props.autocomplete.on": ["Включено", "On", "开启"],
322
317
  "constructor.props.autocomplete.off": ["Выключено", "Off", "关闭"],
323
- "constructor.props.autocomplete.name": ["Полное имя", "Full name", "全名"],
324
- "constructor.props.autocomplete.honorific-prefix": ["Обращение (г-н, г-жа, др.)", "Honorific prefix (Mr., Ms., etc.)", "尊称前缀(先生、女士等)"],
325
318
  "constructor.props.autocomplete.given-name": ["Имя", "Given name", "名"],
326
- "constructor.props.autocomplete.additional-name": ["Отчество", "Additional name", "中间名"],
327
319
  "constructor.props.autocomplete.family-name": ["Фамилия", "Family name", "姓"],
328
- "constructor.props.autocomplete.honorific-suffix": ["Постфикс (мл., ст.)", "Honorific suffix (Jr., Sr.)", "尊称后缀(小、老)"],
329
320
  "constructor.props.autocomplete.nickname": ["Псевдоним", "Nickname", "昵称"],
330
321
  "constructor.props.autocomplete.username": ["Имя пользователя", "Username", "用户名"],
331
322
  "constructor.props.autocomplete.new-password": ["Новый пароль", "New password", "新密码"],
332
323
  "constructor.props.autocomplete.current-password": ["Текущий пароль", "Current password", "当前密码"],
333
- "constructor.props.autocomplete.one-time-code": ["Одноразовый код", "One-time code", "一次性验证码"],
334
324
  "constructor.props.autocomplete.organization-title": ["Должность", "Job title", "职位"],
335
- "constructor.props.autocomplete.organization": ["Организация", "Organization", "组织"],
336
325
  "constructor.props.autocomplete.street-address": ["Адрес, начиная с улицы", "Street address", "街道地址"],
337
- "constructor.props.autocomplete.address-line1": ["Адресная строка 1", "Address line 1", "地址第一行"],
338
- "constructor.props.autocomplete.address-line2": ["Адресная строка 2", "Address line 2", "地址第二行"],
339
- "constructor.props.autocomplete.address-line3": ["Адресная строка 3", "Address line 3", "地址第三行"],
340
- "constructor.props.autocomplete.address-level4": ["Уровень адреса 4", "Address level 4", "地址级别 4"],
341
- "constructor.props.autocomplete.address-level3": ["Уровень адреса 3", "Address level 3", "地址级别 3"],
342
326
  "constructor.props.autocomplete.address-level2": ["Населённый пункт", "City", "城市"],
343
327
  "constructor.props.autocomplete.address-level1": ["Область, регион или штат", "State, province or region", "省/州/地区"],
344
- "constructor.props.autocomplete.country": ["Код страны", "Country code", "国家代码"],
345
328
  "constructor.props.autocomplete.country-name": ["Страна", "Country", "国家"],
346
329
  "constructor.props.autocomplete.postal-code": ["Почтовый индекс", "Postal code", "邮政编码"],
347
- "constructor.props.autocomplete.cc-name": ["Имя владельца карты", "Cardholder name", "持卡人姓名"],
348
- "constructor.props.autocomplete.cc-given-name": ["Имя владельца карты", "Cardholder given name", "持卡人名"],
349
- "constructor.props.autocomplete.cc-additional-name": ["Отчество владельца карты", "Cardholder additional name", "持卡人中间名"],
350
- "constructor.props.autocomplete.cc-family-name": ["Фамилия владельца карты", "Cardholder family name", "持卡人姓"],
351
- "constructor.props.autocomplete.cc-number": ["Номер карты", "Card number", "卡号"],
352
- "constructor.props.autocomplete.cc-exp": ["Срок действия", "Expiration date", "有效期"],
353
- "constructor.props.autocomplete.cc-exp-month": ["Месяц срока действия", "Expiration month", "有效期月份"],
354
- "constructor.props.autocomplete.cc-exp-year": ["Год срока действия", "Expiration year", "有效期年份"],
355
- "constructor.props.autocomplete.cc-csc": ["Код безопасности", "Security code", "安全码"],
356
- "constructor.props.autocomplete.cc-type": ["Тип карты", "Card type", "卡类型"],
357
- "constructor.props.autocomplete.transaction-currency": ["Валюта транзакции", "Transaction currency", "交易货币"],
358
- "constructor.props.autocomplete.transaction-amount": ["Сумма транзакции", "Transaction amount", "交易金额"],
359
- "constructor.props.autocomplete.language": ["Язык", "Language", "语言"],
360
- "constructor.props.autocomplete.bday": ["Дата рождения", "Date of birth", "出生日期"],
361
- "constructor.props.autocomplete.bday-day": ["День рождения", "Birth day", "出生日"],
362
- "constructor.props.autocomplete.bday-month": ["Месяц рождения", "Birth month", "出生月"],
363
- "constructor.props.autocomplete.bday-year": ["Год рождения", "Birth year", "出生年"],
364
- "constructor.props.autocomplete.sex": ["Пол", "Sex", "性别"],
365
- "constructor.props.autocomplete.url": ["URL-адрес", "URL", "URL 地址"],
366
- "constructor.props.autocomplete.photo": ["Фото", "Photo", "照片"],
367
330
  "constructor.props.autocomplete.email": ["Адрес электронной почты", "Email address", "电子邮箱地址"],
368
331
  "constructor.props.autocomplete.tel": ["Полный номер телефона", "Full phone number", "完整电话号码"],
369
- "constructor.props.autocomplete.tel-country-code": ["Код страны телефона", "Phone country code", "电话国家代码"],
370
- "constructor.props.autocomplete.tel-national": ["Национальный номер телефона", "National phone number", "国内电话号码"],
371
- "constructor.props.autocomplete.tel-area-code": ["Код региона/области", "Area code", "区号"],
372
- "constructor.props.autocomplete.tel-local": ["Местный номер", "Local number", "本地号码"],
373
- "constructor.props.autocomplete.tel-local-prefix": ["Префикс местного номера", "Local number prefix", "本地号码前缀"],
374
- "constructor.props.autocomplete.tel-local-suffix": ["Суффикс местного номера", "Local number suffix", "本地号码后缀"],
375
- "constructor.props.autocomplete.tel-extension": ["Добавочный номер", "Extension", "分机号"],
376
- "constructor.props.autocomplete.impp": ["Мессенджер", "Messenger", "即时通讯"],
377
- "constructor.props.autocomplete.fax": ["Номер факса", "Fax number", "传真号码"],
378
332
  };
379
333
  export default translations;
package/dist/options.d.ts CHANGED
@@ -1,3 +1,6 @@
1
+ export declare const findColorOption: <T extends {
2
+ value: string;
3
+ }>(options: T[], classString?: string, prefix?: string) => T | undefined;
1
4
  export declare const optionsStore: import("svelte/store").Readable<{
2
5
  HEADER_OPTIONS: {
3
6
  id: string;
@@ -90,11 +93,6 @@ export declare const optionsStore: import("svelte/store").Readable<{
90
93
  value: string;
91
94
  name: string;
92
95
  }[];
93
- ACCORDION_TYPE_OPTIONS: {
94
- id: string;
95
- value: boolean;
96
- name: string;
97
- }[];
98
96
  FILE_ATTACH_TYPE_OPTIONS: {
99
97
  id: string;
100
98
  value: string;
@@ -130,11 +128,6 @@ export declare const optionsStore: import("svelte/store").Readable<{
130
128
  value: string;
131
129
  name: string;
132
130
  }[];
133
- TABLE_TYPE_OPTIONS: {
134
- id: string;
135
- value: string;
136
- name: string;
137
- }[];
138
131
  TABLE_CONTENT_TYPE_OPTIONS: {
139
132
  id: string;
140
133
  value: string;
@@ -170,9 +163,4 @@ export declare const optionsStore: import("svelte/store").Readable<{
170
163
  value: string;
171
164
  name: string;
172
165
  }[];
173
- AUTOCOMPLETE_OPTIONS: {
174
- id: string;
175
- value: string;
176
- name: string;
177
- }[];
178
166
  }>;
package/dist/options.js CHANGED
@@ -4,6 +4,12 @@ import { T } from "./locales/i18n";
4
4
  function id() {
5
5
  return crypto.randomUUID();
6
6
  }
7
+ /* Достаёт роль master-цвета (класс bg-*) из строки классов компонента и находит соответствующую
8
+ запись в COLOR_OPTIONS — общий хелпер для всех *Props-панелей, где нужно предзаполнить пикер цвета. */
9
+ export const findColorOption = (options, classString, prefix = "bg-") => {
10
+ const colorClass = classString?.split(" ").find((cls) => cls.startsWith(prefix));
11
+ return colorClass ? options.find((c) => c.value.includes(colorClass)) : undefined;
12
+ };
7
13
  export const optionsStore = derived(T, ($T) => {
8
14
  return {
9
15
  HEADER_OPTIONS: [
@@ -143,10 +149,6 @@ export const optionsStore = derived(T, ($T) => {
143
149
  { id: id(), value: "py-2", name: $T("constructor.props.height.medium") },
144
150
  { id: id(), value: "py-3", name: $T("constructor.props.height.large") },
145
151
  ],
146
- ACCORDION_TYPE_OPTIONS: [
147
- { id: id(), value: false, name: $T("constructor.props.type.main") },
148
- { id: id(), value: true, name: $T("constructor.props.type.sub") },
149
- ],
150
152
  FILE_ATTACH_TYPE_OPTIONS: [
151
153
  { id: id(), value: "file", name: $T("constructor.props.type.file") },
152
154
  { id: id(), value: "image", name: $T("constructor.props.type.image") },
@@ -179,10 +181,6 @@ export const optionsStore = derived(T, ($T) => {
179
181
  { id: id(), value: "square", name: $T("constructor.props.type.square") },
180
182
  { id: id(), value: "circle", name: $T("constructor.props.type.circle") },
181
183
  ],
182
- TABLE_TYPE_OPTIONS: [
183
- { id: id(), value: "table", name: $T("constructor.props.table.type.table") },
184
- { id: id(), value: "logger", name: $T("constructor.props.table.type.logger") },
185
- ],
186
184
  TABLE_CONTENT_TYPE_OPTIONS: [
187
185
  { id: id(), value: "text", name: $T("constructor.props.table.type.text") },
188
186
  { id: id(), value: "select", name: $T("constructor.props.table.type.select") },
@@ -247,73 +245,5 @@ export const optionsStore = derived(T, ($T) => {
247
245
  { id: id(), value: "email", name: $T("constructor.props.autocomplete.email") },
248
246
  { id: id(), value: "tel", name: $T("constructor.props.autocomplete.tel") },
249
247
  ],
250
- AUTOCOMPLETE_OPTIONS: [
251
- // Основные значения
252
- { id: id(), value: "on", name: $T("constructor.props.autocomplete.on") },
253
- { id: id(), value: "off", name: $T("constructor.props.autocomplete.off") },
254
- // Имя и фамилия
255
- { id: id(), value: "name", name: $T("constructor.props.autocomplete.name") },
256
- { id: id(), value: "honorific-prefix", name: $T("constructor.props.autocomplete.honorific-prefix") },
257
- { id: id(), value: "given-name", name: $T("constructor.props.autocomplete.given-name") },
258
- { id: id(), value: "additional-name", name: $T("constructor.props.autocomplete.additional-name") },
259
- { id: id(), value: "family-name", name: $T("constructor.props.autocomplete.family-name") },
260
- { id: id(), value: "honorific-suffix", name: $T("constructor.props.autocomplete.honorific-suffix") },
261
- { id: id(), value: "nickname", name: $T("constructor.props.autocomplete.nickname") },
262
- // Пользовательская информация
263
- { id: id(), value: "username", name: $T("constructor.props.autocomplete.username") },
264
- { id: id(), value: "new-password", name: $T("constructor.props.autocomplete.new-password") },
265
- { id: id(), value: "current-password", name: $T("constructor.props.autocomplete.current-password") },
266
- { id: id(), value: "one-time-code", name: $T("constructor.props.autocomplete.one-time-code") },
267
- // Организация
268
- { id: id(), value: "organization-title", name: $T("constructor.props.autocomplete.organization-title") },
269
- { id: id(), value: "organization", name: $T("constructor.props.autocomplete.organization") },
270
- // Адрес
271
- { id: id(), value: "street-address", name: $T("constructor.props.autocomplete.street-address") },
272
- { id: id(), value: "address-line1", name: $T("constructor.props.autocomplete.address-line1") },
273
- { id: id(), value: "address-line2", name: $T("constructor.props.autocomplete.address-line2") },
274
- { id: id(), value: "address-line3", name: $T("constructor.props.autocomplete.address-line3") },
275
- { id: id(), value: "address-level4", name: $T("constructor.props.autocomplete.address-level4") },
276
- { id: id(), value: "address-level3", name: $T("constructor.props.autocomplete.address-level3") },
277
- { id: id(), value: "address-level2", name: $T("constructor.props.autocomplete.address-level2") },
278
- { id: id(), value: "address-level1", name: $T("constructor.props.autocomplete.address-level1") },
279
- { id: id(), value: "country", name: $T("constructor.props.autocomplete.country") },
280
- { id: id(), value: "country-name", name: $T("constructor.props.autocomplete.country-name") },
281
- { id: id(), value: "postal-code", name: $T("constructor.props.autocomplete.postal-code") },
282
- // Контактная информация
283
- { id: id(), value: "cc-name", name: $T("constructor.props.autocomplete.cc-name") },
284
- { id: id(), value: "cc-given-name", name: $T("constructor.props.autocomplete.cc-given-name") },
285
- { id: id(), value: "cc-additional-name", name: $T("constructor.props.autocomplete.cc-additional-name") },
286
- { id: id(), value: "cc-family-name", name: $T("constructor.props.autocomplete.cc-family-name") },
287
- { id: id(), value: "cc-number", name: $T("constructor.props.autocomplete.cc-number") },
288
- { id: id(), value: "cc-exp", name: $T("constructor.props.autocomplete.cc-exp") },
289
- { id: id(), value: "cc-exp-month", name: $T("constructor.props.autocomplete.cc-exp-month") },
290
- { id: id(), value: "cc-exp-year", name: $T("constructor.props.autocomplete.cc-exp-year") },
291
- { id: id(), value: "cc-csc", name: $T("constructor.props.autocomplete.cc-csc") },
292
- { id: id(), value: "cc-type", name: $T("constructor.props.autocomplete.cc-type") },
293
- // Контакт
294
- { id: id(), value: "transaction-currency", name: $T("constructor.props.autocomplete.transaction-currency") },
295
- { id: id(), value: "transaction-amount", name: $T("constructor.props.autocomplete.transaction-amount") },
296
- { id: id(), value: "language", name: $T("constructor.props.autocomplete.language") },
297
- { id: id(), value: "bday", name: $T("constructor.props.autocomplete.bday") },
298
- { id: id(), value: "bday-day", name: $T("constructor.props.autocomplete.bday-day") },
299
- { id: id(), value: "bday-month", name: $T("constructor.props.autocomplete.bday-month") },
300
- { id: id(), value: "bday-year", name: $T("constructor.props.autocomplete.bday-year") },
301
- // Связь
302
- { id: id(), value: "sex", name: $T("constructor.props.autocomplete.sex") },
303
- { id: id(), value: "url", name: $T("constructor.props.autocomplete.url") },
304
- { id: id(), value: "photo", name: $T("constructor.props.autocomplete.photo") },
305
- // Email и телефон
306
- { id: id(), value: "email", name: $T("constructor.props.autocomplete.email") },
307
- { id: id(), value: "tel", name: $T("constructor.props.autocomplete.tel") },
308
- { id: id(), value: "tel-country-code", name: $T("constructor.props.autocomplete.tel-country-code") },
309
- { id: id(), value: "tel-national", name: $T("constructor.props.autocomplete.tel-national") },
310
- { id: id(), value: "tel-area-code", name: $T("constructor.props.autocomplete.tel-area-code") },
311
- { id: id(), value: "tel-local", name: $T("constructor.props.autocomplete.tel-local") },
312
- { id: id(), value: "tel-local-prefix", name: $T("constructor.props.autocomplete.tel-local-prefix") },
313
- { id: id(), value: "tel-local-suffix", name: $T("constructor.props.autocomplete.tel-local-suffix") },
314
- { id: id(), value: "tel-extension", name: $T("constructor.props.autocomplete.tel-extension") },
315
- { id: id(), value: "impp", name: $T("constructor.props.autocomplete.impp") },
316
- { id: id(), value: "fax", name: $T("constructor.props.autocomplete.fax") },
317
- ],
318
248
  };
319
249
  });
@@ -6,10 +6,8 @@
6
6
  /* componentClass — значение вида "bg-red" из optionsStore.COLOR_OPTIONS (или "" — без роли,
7
7
  обычный акцент темы). Возвращает inline-style для корня виджета; пустая строка ничего не переопределяет. */
8
8
  export const widgetAccentStyle = (componentClass) => {
9
- if (!componentClass)
10
- return "";
11
- const role = componentClass.replace(/^bg-/, "");
12
- if (role === "max")
9
+ const role = componentClass.match(/(?:^|\s)bg-(\w+)/)?.[1];
10
+ if (!role || role === "max")
13
11
  return "";
14
12
  return (`--accent-color: var(--${role}-color); --accent-soft: var(--${role}-soft); --accent-hover: var(--${role}-color);` +
15
13
  `--focus-shadow-color: 0 0 0 3px color-mix(in srgb, var(--${role}-color) 18%, transparent);`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "poe-svelte-ui-lib",
3
- "version": "1.28.4",
3
+ "version": "1.28.6",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "scripts": {