poe-svelte-ui-lib 1.2.20 → 1.2.22

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.
@@ -18,7 +18,7 @@
18
18
  </script>
19
19
 
20
20
  <div
21
- {id}
21
+ id={`${id}-${crypto.randomUUID().slice(0, 6)}`}
22
22
  class={twMerge(
23
23
  `${outline ? 'border-none' : 'rounded-xl hover:shadow-md'} w-full
24
24
  border border-(--border-color) bg-(--container-color) p-0 transition-shadow duration-250`,
@@ -163,8 +163,9 @@
163
163
 
164
164
  <UI.Switch
165
165
  label={{ name: $t('constructor.props.open') }}
166
- value={component.properties.isOpen ? 2 : 1}
167
- onChange={(value) => updateProperty('isOpen', value === 2, component, onPropertyChange)}
166
+ value={component.properties.isOpen}
167
+ options={[{ id: crypto.randomUUID(), value: 0, class: '' }]}
168
+ onChange={(value) => updateProperty('isOpen', value, component, onPropertyChange)}
168
169
  />
169
170
  </div>
170
171
  <div class="flex w-1/3 flex-col items-center px-2">
@@ -67,7 +67,7 @@
67
67
 
68
68
  <div class={twMerge(`relative flex w-full flex-col items-center `, wrapperClass)}>
69
69
  <button
70
- {id}
70
+ id={`${id}-${crypto.randomUUID().slice(0, 6)}`}
71
71
  class="{twMerge(
72
72
  `relative m-0 inline-block w-full items-center rounded-2xl
73
73
  px-2 py-1 font-semibold transition duration-200 select-none
@@ -141,8 +141,9 @@
141
141
  <UI.Switch
142
142
  wrapperClass="bg-blue"
143
143
  label={{ name: $t('constructor.props.disabled') }}
144
- value={component.properties.disabled ? 2 : 1}
145
- onChange={(value) => updateProperty('disabled', value === 2, component, onPropertyChange)}
144
+ value={component.properties.disabled}
145
+ options={[{ id: crypto.randomUUID(), value: 0, class: '' }]}
146
+ onChange={(value) => updateProperty('disabled', value, component, onPropertyChange)}
146
147
  />
147
148
  </div>
148
149
  <div class="flex w-1/3 flex-col px-2">
@@ -129,7 +129,7 @@
129
129
  })
130
130
  </script>
131
131
 
132
- <div {id} class={twMerge(`relative flex w-full flex-col items-center`, wrapperClass)}>
132
+ <div id={`${id}-${crypto.randomUUID().slice(0, 6)}`} class={twMerge(`relative flex w-full flex-col items-center`, wrapperClass)}>
133
133
  {#if label.name}
134
134
  <h5 class={twMerge(`w-full px-4 text-center`, label.class)}>{label.name}</h5>
135
135
  {/if}
@@ -77,12 +77,19 @@
77
77
  <span class="text-sm text-gray-500">Image</span>
78
78
  {/if}
79
79
  </button>
80
- <input {id} type="file" class="absolute -z-10 h-0 w-0 overflow-hidden opacity-0" {accept} {disabled} onchange={handleFileChange} />
80
+ <input
81
+ id={`${id}-${crypto.randomUUID().slice(0, 6)}`}
82
+ type="file"
83
+ class="absolute -z-10 h-0 w-0 overflow-hidden opacity-0"
84
+ {accept}
85
+ {disabled}
86
+ onchange={handleFileChange}
87
+ />
81
88
  </div>
82
89
  {:else}
83
90
  <label class="relative inline-block w-full">
84
91
  <input
85
- {id}
92
+ id={`${id}-${crypto.randomUUID().slice(0, 6)}`}
86
93
  type="file"
87
94
  class={`h-8.5 w-full rounded-2xl bg-(--back-color) font-semibold shadow-sm transition duration-250 hover:shadow-md
88
95
  ${disabled ? 'cursor-not-allowed opacity-50' : 'cursor-pointer'} invalid:shadow-[0_0_6px(--red-color) file:h-full file:w-1/3
@@ -218,7 +218,7 @@
218
218
  }
219
219
  </script>
220
220
 
221
- <div {id} class={`relative flex w-full flex-col items-center justify-center ${wrapperClass}`}>
221
+ <div id={`${id}-${crypto.randomUUID().slice(0, 6)}`} class={`relative flex w-full flex-col items-center justify-center ${wrapperClass}`}>
222
222
  {#if label.name}
223
223
  <h5 class={`w-full px-4 text-center ${label.class}`}>{label.name}</h5>
224
224
  {/if}
@@ -67,8 +67,9 @@
67
67
  <UI.Switch
68
68
  wrapperClass="bg-blue"
69
69
  label={{ name: $t('constructor.props.istest') }}
70
- value={component.properties.isTest ? 2 : 1}
71
- onChange={(value) => updateProperty('isTest', value === 2, component, onPropertyChange)}
70
+ value={component.properties.isTest}
71
+ options={[{ id: crypto.randomUUID(), value: 0, class: '' }]}
72
+ onChange={(value) => updateProperty('isTest', value, component, onPropertyChange)}
72
73
  />
73
74
  </div>
74
75
  </div>
@@ -74,7 +74,7 @@
74
74
  componentClass,
75
75
  )}
76
76
  style="background: color-mix(in srgb, var(--bg-color), var(--back-color) 70%);"
77
- {id}
77
+ id={`${id}-${crypto.randomUUID().slice(0, 6)}`}
78
78
  {placeholder}
79
79
  {disabled}
80
80
  autocomplete={help?.autocomplete}
@@ -99,7 +99,7 @@
99
99
  componentClass,
100
100
  )}
101
101
  style="background: color-mix(in srgb, var(--bg-color), var(--back-color) 70%);"
102
- {id}
102
+ id={`${id}-${crypto.randomUUID().slice(0, 6)}`}
103
103
  {disabled}
104
104
  {maxlength}
105
105
  rows={textareaRows}
@@ -161,13 +161,15 @@
161
161
  />
162
162
  <UI.Switch
163
163
  label={{ name: $t('constructor.props.readonly') }}
164
- value={component.properties.readonly ? 2 : 1}
165
- onChange={(value) => updateProperty('readonly', value === 2)}
164
+ value={component.properties.readonly}
165
+ options={[{ id: crypto.randomUUID(), value: 0, class: '' }]}
166
+ onChange={(value) => updateProperty('readonly', value)}
166
167
  />
167
168
  <UI.Switch
168
169
  label={{ name: $t('constructor.props.copy') }}
169
- value={component.properties.help.copyButton ? 2 : 1}
170
- onChange={(value) => updateProperty('help.copyButton', value === 2)}
170
+ value={component.properties.help.copyButton}
171
+ options={[{ id: crypto.randomUUID(), value: 0, class: '' }]}
172
+ onChange={(value) => updateProperty('help.copyButton', value)}
171
173
  />
172
174
  </div>
173
175
  <div class="flex w-1/3 flex-col px-2">
@@ -320,18 +322,21 @@
320
322
 
321
323
  <UI.Switch
322
324
  label={{ name: $t('constructor.props.readonly') }}
323
- value={component.properties.readonly ? 2 : 1}
324
- onChange={(value) => updateProperty('readonly', value === 2)}
325
+ value={component.properties.readonly}
326
+ options={[{ id: crypto.randomUUID(), value: 0, class: '' }]}
327
+ onChange={(value) => updateProperty('readonly', value)}
325
328
  />
326
329
  <UI.Switch
327
330
  label={{ name: $t('constructor.props.copy') }}
328
- value={component.properties.help.copyButton ? 2 : 1}
329
- onChange={(value) => updateProperty('help.copyButton', value === 2)}
331
+ value={component.properties.help.copyButton}
332
+ options={[{ id: crypto.randomUUID(), value: 0, class: '' }]}
333
+ onChange={(value) => updateProperty('help.copyButton', value)}
330
334
  />
331
335
  <UI.Switch
332
336
  label={{ name: $t('constructor.props.disabled') }}
333
- value={component.properties.disabled ? 2 : 1}
334
- onChange={(value) => updateProperty('disabled', value === 2)}
337
+ value={component.properties.disabled}
338
+ options={[{ id: crypto.randomUUID(), value: 0, class: '' }]}
339
+ onChange={(value) => updateProperty('disabled', value)}
335
340
  />
336
341
  </div>
337
342
  </div>
@@ -166,13 +166,14 @@
166
166
  let angle = 360 / directions.length
167
167
  </script>
168
168
 
169
- <div {id} class={twMerge(`bg-blue relative flex w-full flex-col items-center`, wrapperClass)}>
169
+ <div id={`${id}-${crypto.randomUUID().slice(0, 6)}`} class={twMerge(`bg-red relative flex w-full flex-col items-center`, wrapperClass)}>
170
170
  {#if label.name}
171
171
  <h5 class={twMerge(` w-full px-4 text-center`, label.class)}>{label.name}</h5>
172
172
  {/if}
173
173
 
174
- <div class=" flex items-center justify-center">
174
+ <div class=" flex w-1/2 items-center justify-center">
175
175
  <div class="relative z-10 flex size-40 items-center justify-center rounded-full bg-(--bg-color) shadow-[0_0_20px_rgb(0_0_0_/0.25)]">
176
+ <!-- Основные кнопки (оси pitch и yaw) -->
176
177
  <div class="absolute h-full w-full overflow-hidden rounded-full">
177
178
  {#each directions as direction, index}
178
179
  <button
@@ -205,6 +206,7 @@
205
206
  </button>
206
207
  {/each}
207
208
  </div>
209
+ <!-- Линии для разделения на сектора -->
208
210
  <div class="pointer-events-none absolute h-full w-full overflow-hidden rounded-full">
209
211
  {#each directions as direction, index}
210
212
  <span
@@ -216,6 +218,7 @@
216
218
  </span>
217
219
  {/each}
218
220
  </div>
221
+ <!-- Кнопка домой -->
219
222
  <div
220
223
  class="z-20 flex size-20 items-center justify-center rounded-full bg-(--bg-color) shadow-[0_0_15px_rgb(0_0_0_/0.25)] transition hover:scale-103"
221
224
  >
@@ -235,6 +238,7 @@
235
238
  >
236
239
  </div>
237
240
  </div>
241
+ <!-- Боковые кнопки (ось roll) -->
238
242
  <div
239
243
  class="absolute flex h-15 w-65 items-center justify-between rounded-full shadow-[0_0_15px_rgb(0_0_0_/0.25)]"
240
244
  style="background: color-mix(in srgb, var(--bg-color), var(--shadow-color) 10%)"
@@ -288,40 +292,50 @@
288
292
  </div>
289
293
  </div>
290
294
 
291
- <p>{value[0]}</p>
292
- <p>{value[1]}</p>
293
- <p>{value[2]}</p>
294
-
295
- <div {id} class="flex h-full w-full flex-row justify-center rounded-full p-10">
296
- {#each sensitivityOptions as option, index}
297
- <button
298
- id={crypto.randomUUID()}
299
- class={twMerge(`m-0 inline-block min-w-0 flex-1 cursor-pointer items-center px-2 py-1 font-semibold shadow-sm transition-all duration-300
295
+ <div class="absolute right-10 flex items-center">
296
+ <div id={`${id}-${crypto.randomUUID().slice(0, 6)}`} class="flex h-full flex-col justify-center rounded-full p-10">
297
+ {#each sensitivityOptions as option, index}
298
+ <button
299
+ id={crypto.randomUUID()}
300
+ class={twMerge(`m-0 inline-block min-w-0 flex-1 cursor-pointer items-center px-2 py-1 font-semibold shadow-sm transition-all duration-300
300
301
  select-none hover:shadow-md
301
302
  ${
302
303
  option === sensitivity && sensitivity !== null
303
304
  ? 'z-10 py-1 shadow-[0_0_10px_var(--shadow-color)] hover:shadow-[0_0_15px_var(--shadow-color)]'
304
305
  : ''
305
306
  }
306
- ${sensitivityOptions.length > 0 && index === 0 ? 'rounded-l-2xl' : ''} ${
307
- index === sensitivityOptions.length - 1 ? 'rounded-r-2xl' : ''
307
+ ${sensitivityOptions.length > 0 && index === 0 ? 'rounded-t-2xl' : ''} ${
308
+ index === sensitivityOptions.length - 1 ? 'rounded-b-2xl' : ''
308
309
  } bg-(--back-color)`)}
309
- onclick={() => {
310
- sensitivity = option
311
- }}
312
- >
313
- <span class="flex flex-row items-center justify-center gap-4">
314
- {#if option}
315
- <div class="flex-1">
316
- {option}
317
- </div>
318
- {/if}
319
- </span>
320
- </button>
321
- {/each}
310
+ onclick={() => {
311
+ sensitivity = option
312
+ }}
313
+ >
314
+ <span class="flex flex-row items-center justify-center gap-4">
315
+ {#if option}
316
+ <div class="flex-1">
317
+ {option}
318
+ </div>
319
+ {/if}
320
+ </span>
321
+ </button>
322
+ {/each}
323
+ </div>
324
+
325
+ <div>
326
+ {#each [0, 1, 2] as num}
327
+ <h5 class={twMerge(` w-full px-4 text-center`, label.class)}>{num == 0 ? 'Roll' : num == 1 ? 'Pitch' : 'Yaw'}</h5>
328
+ <input
329
+ class={`w-20 rounded-2xl border border-(--border-color) px-4 py-1 text-center transition-all duration-300 outline-none
330
+ hover:shadow-md
331
+ [&::-webkit-inner-spin-button]:hidden
332
+ [&::-webkit-outer-spin-button]:hidden`}
333
+ style="background: color-mix(in srgb, var(--bg-color), var(--back-color) 70%);"
334
+ value={sensitivity == 0.01 ? value[num].toFixed(2) : sensitivity == 0.1 ? value[num].toFixed(1) : value[num].toFixed(0)}
335
+ id={`${id}-${crypto.randomUUID().slice(0, 6)}`}
336
+ readonly
337
+ />
338
+ {/each}
339
+ </div>
322
340
  </div>
323
- <!-- {direction.content ? 2 * 6.25 * Math.sin((Math.PI * 65) / 360) : 2 * 6.25 * Math.sin((Math.PI * 25) / 360)} -->
324
- <!-- angle / 2 + angle * index -->
325
- <!-- ? 'shadow-[0_-2px_5px_rgb(254_202_202)] '
326
- : 'shadow-[0_2px_5px_rgb(254_202_202)]'}" -->
327
341
  </div>
@@ -40,7 +40,7 @@
40
40
  })
41
41
  </script>
42
42
 
43
- <div {id} class={twMerge(`relative flex w-full flex-col items-center`, wrapperClass)}>
43
+ <div id={`${id}-${crypto.randomUUID().slice(0, 6)}`} class={twMerge(`relative flex w-full flex-col items-center`, wrapperClass)}>
44
44
  {#if label.name}
45
45
  <h5 class={twMerge(` w-full px-4 text-center`, label.class)}>{label.name}</h5>
46
46
  {/if}
@@ -92,7 +92,7 @@
92
92
  {/if}
93
93
  {#if type === 'select'}
94
94
  <button
95
- {id}
95
+ id={`${id}-${crypto.randomUUID().slice(0, 6)}`}
96
96
  value={value?.value ? String(value.value) : ''}
97
97
  class={twMerge(
98
98
  `w-full rounded-2xl border border-(--border-color) p-1 text-center duration-250
@@ -133,7 +133,7 @@
133
133
  </div>
134
134
  {/if}
135
135
  {:else if type === 'buttons'}
136
- <div {id} class="flex h-full w-full flex-row justify-center rounded-full border border-(--bg-color)">
136
+ <div id={`${id}-${crypto.randomUUID().slice(0, 6)}`} class="flex h-full w-full flex-row justify-center rounded-full border border-(--bg-color)">
137
137
  {#each options as option, index (option.id)}
138
138
  <button
139
139
  id={option.id}
@@ -165,7 +165,7 @@
165
165
  [&::-webkit-inner-spin-button]:hidden [&::-webkit-outer-spin-button]:hidden
166
166
  {disabled ? 'cursor-not-allowed opacity-50' : 'cursor-text'} border-(--border-color)"
167
167
  style="background: color-mix(in srgb, var(--bg-color), var(--back-color) 70%);"
168
- {id}
168
+ id={`${id}-${crypto.randomUUID().slice(0, 6)}`}
169
169
  {disabled}
170
170
  oninput={(e) => handleSearch((e.currentTarget as HTMLInputElement).value)}
171
171
  onclick={(e) => {
@@ -232,8 +232,9 @@
232
232
  <UI.Switch
233
233
  wrapperClass="bg-blue"
234
234
  label={{ name: $t('constructor.props.disabled') }}
235
- value={component.properties.disabled ? 2 : 1}
236
- onChange={(value) => updateProperty('disabled', value === 2, component, onPropertyChange)}
235
+ value={component.properties.disabled }
236
+ options={[{ id: crypto.randomUUID(), value: 0, class: '' }]}
237
+ onChange={(value) => updateProperty('disabled', value , component, onPropertyChange)}
237
238
  />
238
239
  </div>
239
240
  <div class="flex w-1/3 flex-col items-center px-2">
@@ -98,7 +98,10 @@
98
98
  {/if}
99
99
 
100
100
  <!-- Слайдер -->
101
- <div {id} class="relative flex h-7 w-full justify-center rounded-full {disabled ? 'cursor-not-allowed opacity-50' : ''}">
101
+ <div
102
+ id={`${id}-${crypto.randomUUID().slice(0, 6)}`}
103
+ class="relative flex h-7 w-full justify-center rounded-full {disabled ? 'cursor-not-allowed opacity-50' : ''}"
104
+ >
102
105
  {#if isRange}
103
106
  <!-- Трек и активная зона -->
104
107
  <div
@@ -138,8 +138,9 @@
138
138
  <UI.Switch
139
139
  wrapperClass="bg-blue"
140
140
  label={{ name: $t('constructor.props.disabled') }}
141
- value={component.properties.disabled ? 2 : 1}
142
- onChange={(value) => updateProperty('disabled', value === 2, component, onPropertyChange)}
141
+ value={component.properties.disabled}
142
+ options={[{ id: crypto.randomUUID(), value: 0, class: '' }]}
143
+ onChange={(value) => updateProperty('disabled', value, component, onPropertyChange)}
143
144
  />
144
145
  </div>
145
146
  <div class="flex w-1/3 flex-col px-2">
@@ -5,39 +5,42 @@
5
5
 
6
6
  let {
7
7
  id = crypto.randomUUID(),
8
- disabled = false,
9
8
  wrapperClass = '',
10
9
  label = { name: '', class: '', captionLeft: '', captionRight: '' },
11
10
  height = '2rem',
12
11
  type = 'horizontal',
12
+ options = [],
13
+ bitMode = false,
13
14
  value = $bindable(),
14
15
  onChange = () => {},
15
16
  }: ISwitchProps = $props()
16
17
 
17
- const options = [1, 2]
18
- let checked = $derived(value === options[1])
18
+ let localOptions = $derived(bitMode ? options : options.slice(0, 1))
19
19
 
20
- let knobTransform = $derived(
21
- checked
22
- ? `${type === 'horizontal' ? `translateX(calc(${height}))` : `translateY(calc(-${height}/2))`}`
23
- : `${type === 'horizontal' ? 'translateX(0)' : `translateY(calc(${height}/2))`}`,
20
+ let checkedOptions: boolean[] = $derived(
21
+ (() => {
22
+ if (bitMode) {
23
+ return localOptions.map((option) => ((value ?? 0) & (1 << (option?.value ?? 0))) == Math.pow(2, option.value ?? 0))
24
+ } else {
25
+ return [value == 1]
26
+ }
27
+ })(),
24
28
  )
29
+ let ID = $derived(`${id}-${crypto.randomUUID().slice(0, 6)}`)
25
30
 
26
31
  $effect(() => {
27
- if (value === undefined || value === null) value = options[0]
32
+ if (value === undefined || value === null) value = 0
28
33
  })
29
34
 
30
- const handleToggle = () => {
31
- if (disabled) return
32
- const newValue = checked ? options[1] : options[0]
35
+ const handleToggle = (index: number) => {
36
+ if (localOptions[index].disabled) return
37
+ value = (value ?? 0) ^ (1 << (localOptions[index].value ?? 0))
33
38
 
34
- value = newValue
35
-
36
- onChange(newValue)
39
+ onChange(value)
37
40
  }
38
41
 
39
42
  const handleCaptionClick = (newValue: number) => {
40
- if (disabled || value === newValue) return
43
+ if (localOptions[0].disabled || value === newValue) return
41
44
  value = newValue
42
45
  onChange(newValue)
43
46
  }
@@ -50,67 +53,81 @@
50
53
  </script>
51
54
 
52
55
  {#if type !== 'checkbox'}
53
- <div class={twMerge(`bg-blue relative flex w-full flex-col items-center justify-center`, wrapperClass)}>
56
+ <div class={twMerge(`relative flex w-full flex-col items-center justify-center`, wrapperClass)}>
54
57
  {#if label.name}
55
58
  <h5 class={twMerge(`w-full px-4 text-center`, label.class)}>{label.name}</h5>
56
59
  {/if}
60
+ <div class="flex w-full flex-wrap justify-center gap-5">
61
+ {#each localOptions as option, index}
62
+ <div class={twMerge(`bg-blue flex flex-col`, option.class)}>
63
+ {#if option.name}
64
+ <span>{option.name}</span>
65
+ {/if}
66
+
67
+ <div class="relative flex w-full grow items-center justify-center bg-transparent">
68
+ {#if type === 'horizontal' && label.captionLeft}
69
+ <button
70
+ class="mr-2 {option.disabled ? 'opacity-60' : 'cursor-pointer'}"
71
+ style="width: {maxCaptionWidth}; text-align: end;"
72
+ onclick={() => handleCaptionClick(0)}>{label.captionLeft}</button
73
+ >
74
+ {/if}
57
75
 
58
- <div class="relative flex w-full grow items-center justify-center bg-transparent">
59
- {#if type === 'horizontal'}
60
- <button
61
- class="mr-2 {disabled ? 'opacity-60' : 'cursor-pointer'}"
62
- style="width: {maxCaptionWidth}; text-align: end;"
63
- onclick={() => handleCaptionClick(1)}>{label.captionLeft}</button
64
- >
65
- {/if}
76
+ <label
77
+ class="relative flex items-center justify-between rounded-full border
78
+ {checkedOptions[index] ? 'border-(--bg-color)' : 'border-(--gray-color)'}
79
+ {option.disabled ? 'opacity-60' : ''}"
80
+ >
81
+ <input
82
+ id={`${id}-${crypto.randomUUID().slice(0, 6)}`}
83
+ type="checkbox"
84
+ class="absolute left-1/2 h-full w-full -translate-x-1/2 cursor-pointer appearance-none rounded-md"
85
+ checked={checkedOptions[index]}
86
+ disabled={option.disabled}
87
+ onchange={() => handleToggle(index)}
88
+ />
89
+ <span
90
+ class="relative flex items-center rounded-full transition-all duration-250
91
+ {checkedOptions[index] ? 'bg-(--bg-color)' : 'bg-(--gray-color)'}
92
+ {option.disabled ? '' : 'cursor-pointer'}"
93
+ style="{type === 'horizontal' ? 'width' : 'height'}: {`calc(${height} * 2)`}; {type === 'horizontal' ? 'height' : 'width'}: {height};"
94
+ >
95
+ <span
96
+ class="absolute rounded-full bg-(--back-color) transition-all duration-250
97
+ {option.disabled ? 'opacity-60' : 'cursor-pointer'}"
98
+ style="width: {`calc(${height} * 0.8)`}; height: {`calc(${height} * 0.8)`}; margin: 0 {`calc(${height} * 0.1)`}; transform: {checkedOptions[
99
+ index
100
+ ]
101
+ ? `${type === 'horizontal' ? `translateX(calc(${height}))` : `translateY(calc(-${height}/2))`}`
102
+ : `${type === 'horizontal' ? 'translateX(0)' : `translateY(calc(${height}/2))`}`};"
103
+ ></span>
104
+ </span>
105
+ </label>
66
106
 
67
- <label
68
- class="relative flex items-center justify-between rounded-full border
69
- {checked ? 'border-(--bg-color)' : 'border-(--gray-color)'}
70
- {disabled ? 'opacity-60' : ''}"
71
- >
72
- <input
73
- {id}
74
- type="checkbox"
75
- class="absolute left-1/2 h-full w-full -translate-x-1/2 cursor-pointer appearance-none rounded-md"
76
- bind:checked
77
- {disabled}
78
- onchange={handleToggle}
79
- />
80
- <span
81
- class="relative flex items-center rounded-full transition-all duration-250
82
- {checked ? 'bg-(--bg-color)' : 'bg-(--gray-color)'}
83
- {disabled ? '' : 'cursor-pointer'}"
84
- style="{type === 'horizontal' ? 'width' : 'height'}: {`calc(${height} * 2)`}; {type === 'horizontal' ? 'height' : 'width'}: {height};"
85
- >
86
- <span
87
- class="absolute rounded-full bg-(--back-color) transition-all duration-250
88
- {disabled ? 'opacity-60' : 'cursor-pointer'}"
89
- style="width: {`calc(${height} * 0.8)`}; height: {`calc(${height} * 0.8)`}; margin: 0 {`calc(${height} * 0.1)`}; transform: {knobTransform};"
90
- ></span>
91
- </span>
92
- </label>
93
- {#if type === 'horizontal'}
94
- <button
95
- class="ml-2 {disabled ? 'opacity-60' : 'cursor-pointer'}"
96
- style="width: {maxCaptionWidth}; text-align: start;"
97
- onclick={() => handleCaptionClick(2)}>{label.captionRight}</button
98
- >
99
- {/if}
107
+ {#if type === 'horizontal' && label.captionRight}
108
+ <button
109
+ class="ml-2 {option.disabled ? 'opacity-60' : 'cursor-pointer'}"
110
+ style="width: {maxCaptionWidth}; text-align: start;"
111
+ onclick={() => handleCaptionClick(1)}>{label.captionRight}</button
112
+ >
113
+ {/if}
114
+ </div>
115
+ </div>
116
+ {/each}
100
117
  </div>
101
118
  </div>
102
119
  {:else}
103
120
  <div class={twMerge('bg-blue m-1 flex items-center justify-center gap-2', wrapperClass)}>
104
121
  <input
105
- {id}
122
+ id={ID}
106
123
  type="checkbox"
107
- bind:checked
108
- {disabled}
124
+ bind:checked={checkedOptions[0]}
125
+ disabled={localOptions[0].disabled}
109
126
  class="
110
127
  relative size-8 cursor-pointer appearance-none rounded-2xl border border-(--bg-color)
111
128
  bg-white transition duration-300 after:origin-bottom-left after:opacity-0
112
129
  checked:border-(--bg-color)
113
- checked:bg-(--bg-color) checked:after:absolute checked:after:left-[5.5px]
130
+ checked:bg-(--bg-color) checked:after:absolute checked:after:-top-px checked:after:left-[5.5px]
114
131
  checked:after:h-[13.5px] checked:after:w-[7.5px] checked:after:rotate-43
115
132
  checked:after:border-2 checked:after:border-t-0
116
133
  checked:after:border-l-0 checked:after:border-solid
@@ -118,9 +135,9 @@
118
135
  checked:after:content-[''] hover:shadow-md
119
136
  disabled:cursor-not-allowed disabled:opacity-70
120
137
  "
121
- onchange={handleToggle}
138
+ onchange={() => handleToggle(0)}
122
139
  />
123
- <label for={id} class={twMerge("{disabled ? 'cursor-not-allowed opacity-70' : 'cursor-pointer'} ml-1 select-none", label.class)}>
140
+ <label for={ID} class={twMerge("{disabled ? 'cursor-not-allowed opacity-70' : 'cursor-pointer'} ml-1 select-none", label.class)}>
124
141
  {label.name}
125
142
  </label>
126
143
  </div>
@@ -5,6 +5,8 @@
5
5
  import * as UI from '..'
6
6
  import { optionsStore } from '../options'
7
7
  import { twMerge } from 'tailwind-merge'
8
+ import ButtonDelete from '../libIcons/ButtonDelete.svelte'
9
+ import ButtonAdd from '../libIcons/ButtonAdd.svelte'
8
10
 
9
11
  const {
10
12
  component,
@@ -47,41 +49,160 @@
47
49
  updateProperty('eventHandler.Argument', option.value as string, component, onPropertyChange)
48
50
  }}
49
51
  />
52
+ {#if !component.properties.bitMode}
53
+ <UI.Select
54
+ wrapperClass="!h-14"
55
+ label={{ name: $t('constructor.props.type') }}
56
+ type="buttons"
57
+ options={$optionsStore.SWITCH_OPTIONS}
58
+ value={$optionsStore.SWITCH_OPTIONS.find((option) => option.value == component.properties.type)}
59
+ onUpdate={(option) => updateProperty('type', option.value as string, component, onPropertyChange)}
60
+ />
61
+ {/if}
50
62
  </div>
51
- <div class="flex w-1/3 flex-col px-2">
52
- <UI.Input
53
- label={{ name: $t('constructor.props.caption.left') }}
54
- value={component.properties.label.captionLeft}
55
- onUpdate={(value) => updateProperty('label.captionLeft', value as string, component, onPropertyChange)}
56
- />
57
- <UI.Input
58
- label={{ name: $t('constructor.props.caption.right') }}
59
- value={component.properties.label.captionRight}
60
- onUpdate={(value) => updateProperty('label.captionRight', value as string, component, onPropertyChange)}
61
- />
62
- <UI.Switch
63
- wrapperClass="bg-blue"
64
- label={{ name: $t('constructor.props.disabled') }}
65
- value={component.properties.disabled ? 2 : 1}
66
- onChange={(value) => updateProperty('disabled', value === 2, component, onPropertyChange)}
67
- />
68
- </div>
63
+ {#if !component.properties.bitMode}
64
+ <div class="flex w-1/3 flex-col px-2">
65
+ <UI.Input
66
+ label={{ name: $t('constructor.props.caption.left') }}
67
+ value={component.properties.label.captionLeft}
68
+ onUpdate={(value) => updateProperty('label.captionLeft', value as string, component, onPropertyChange)}
69
+ />
70
+ <UI.Input
71
+ label={{ name: $t('constructor.props.caption.right') }}
72
+ value={component.properties.label.captionRight}
73
+ onUpdate={(value) => updateProperty('label.captionRight', value as string, component, onPropertyChange)}
74
+ />
75
+
76
+ <UI.Switch
77
+ wrapperClass="bg-blue"
78
+ label={{ name: $t('constructor.props.disabled') }}
79
+ value={component.properties.options[0].disabled}
80
+ options={[{ id: crypto.randomUUID(), value: 0, class: '' }]}
81
+ onChange={(value) => {
82
+ const options = [...(component.properties?.options || [])]
83
+ options[0]['disabled'] = value
84
+ updateProperty('options', options, component, onPropertyChange)
85
+ }}
86
+ />
87
+ </div>
88
+ {/if}
69
89
  <div class="flex w-1/3 flex-col px-2">
70
90
  <UI.Input
71
91
  label={{ name: $t('constructor.props.label') }}
72
92
  value={component.properties.label.name}
73
93
  onUpdate={(value) => updateProperty('label.name', value as string, component, onPropertyChange)}
74
94
  />
75
- <UI.Select
76
- wrapperClass="!h-14"
77
- label={{ name: $t('constructor.props.colors') }}
78
- type="buttons"
79
- options={$optionsStore.COLOR_OPTIONS.filter((option) => option.value !== 'bg-max' && option.value !== 'bg-gray')}
80
- value={initialColor}
81
- onUpdate={(option) => updateProperty('wrapperClass', twMerge(component.properties.wrapperClass, option.value), component, onPropertyChange)}
95
+ {#if !component.properties.bitMode}
96
+ <UI.Select
97
+ wrapperClass="!h-14"
98
+ label={{ name: $t('constructor.props.colors') }}
99
+ type="buttons"
100
+ options={$optionsStore.COLOR_OPTIONS.filter((option) => option.value !== 'bg-max' && option.value !== 'bg-gray')}
101
+ value={initialColor}
102
+ onUpdate={(option) => {
103
+ const options = [...(component.properties?.options || [])]
104
+ options[0]['class'] = option.value
105
+ updateProperty('options', options, component, onPropertyChange)
106
+ }}
107
+ />
108
+ {/if}
109
+ <UI.Switch
110
+ wrapperClass="bg-blue"
111
+ label={{ name: $t('constructor.props.bitmode') }}
112
+ value={component.properties.bitMode}
113
+ options={[{ id: crypto.randomUUID(), value: 0, class: '' }]}
114
+ onChange={(value) => {
115
+ updateProperty('bitMode', value, component, onPropertyChange)
116
+ updateProperty('value', 1, component, onPropertyChange)
117
+ }}
82
118
  />
83
119
  </div>
84
120
  </div>
121
+ {#if component.properties.bitMode}
122
+ <hr class="border-gray-400" />
123
+
124
+ <!-- Настройки опций -->
125
+ <div class="space-y-4">
126
+ <div class="m-0 flex items-center justify-center gap-2">
127
+ <h4>{$t('constructor.props.bits.title')}</h4>
128
+ <UI.Button
129
+ wrapperClass="w-8"
130
+ content={{ icon: ButtonAdd }}
131
+ onClick={() => {
132
+ const newOption: ISelectOption = {
133
+ id: crypto.randomUUID(),
134
+ name: `Option ${component.properties?.options.length + 1}`,
135
+ value: component.properties?.options.length,
136
+ class: 'bg-blue',
137
+ }
138
+ const options = [...(component.properties?.options || []), newOption]
139
+ updateProperty('options', options, component, onPropertyChange)
140
+ }}
141
+ />
142
+ </div>
143
+
144
+ {#each component.properties.options || [] as option, index (option.id)}
145
+ <div class="m-0 flex items-end justify-around gap-2 border-gray-400">
146
+ <UI.Input
147
+ label={{ name: $t('constructor.props.optionname') }}
148
+ wrapperClass="!w-3/10"
149
+ value={option.name}
150
+ onUpdate={(value) => {
151
+ const options = [...(component.properties?.options || [])]
152
+ options[index]['name'] = value
153
+ updateProperty('options', options, component, onPropertyChange)
154
+ }}
155
+ />
156
+ <UI.Input
157
+ label={{ name: $t('constructor.props.optionvalue') }}
158
+ wrapperClass="!w-3/10"
159
+ value={option.value}
160
+ type="number"
161
+ number={{ minNum: 0, maxNum: 31, step: 1 }}
162
+ onUpdate={(value) => {
163
+ const options = [...(component.properties?.options || [])]
164
+ options[index]['value'] = value
165
+ updateProperty('options', options, component, onPropertyChange)
166
+ }}
167
+ />
168
+ <UI.Select
169
+ wrapperClass="w-80 h-14.5"
170
+ label={{ name: $t('constructor.props.colors') }}
171
+ type="buttons"
172
+ options={$optionsStore.COLOR_OPTIONS.filter((option) => option.value !== 'bg-max' && option.value !== 'bg-gray')}
173
+ value={$optionsStore.COLOR_OPTIONS.find((c) =>
174
+ (c.value as string).includes(option.class.split(' ').find((cls: string) => cls.startsWith('bg-'))),
175
+ )}
176
+ onUpdate={(option) => {
177
+ const options = [...(component.properties?.options || [])]
178
+ options[index]['class'] = option.value
179
+ updateProperty('options', options, component, onPropertyChange)
180
+ }}
181
+ />
182
+ <UI.Switch
183
+ wrapperClass=" w-1/10 bg-blue"
184
+ label={{ name: $t('constructor.props.disabled') }}
185
+ value={option.disabled}
186
+ options={[{ id: crypto.randomUUID(), value: 0, class: '' }]}
187
+ onChange={(value) => {
188
+ const options = [...(component.properties?.options || [])]
189
+ options[index]['disabled'] = value
190
+ updateProperty('options', options, component, onPropertyChange)
191
+ }}
192
+ />
193
+ <UI.Button
194
+ wrapperClass="w-8"
195
+ content={{ icon: ButtonDelete }}
196
+ onClick={() => {
197
+ const options = [...(component.properties?.options || [])]
198
+ options.splice(index, 1)
199
+ updateProperty('options', options, component, onPropertyChange)
200
+ }}
201
+ />
202
+ </div>
203
+ {/each}
204
+ </div>
205
+ {/if}
85
206
  {:else}
86
207
  <div class="relative flex flex-row items-start justify-center">
87
208
  <!-- Сообщение для отправки в ws по нажатию кнопки -->
@@ -128,6 +249,14 @@
128
249
  value={component.properties.label.captionRight}
129
250
  onUpdate={(value) => updateProperty('label.captionRight', value as string, component, onPropertyChange)}
130
251
  />
252
+ <UI.Select
253
+ wrapperClass="!h-14"
254
+ label={{ name: $t('constructor.props.type') }}
255
+ type="buttons"
256
+ options={$optionsStore.SWITCH_OPTIONS}
257
+ value={$optionsStore.SWITCH_OPTIONS.find((option) => option.value == component.properties.type)}
258
+ onUpdate={(option) => updateProperty('type', option.value as string, component, onPropertyChange)}
259
+ />
131
260
  </div>
132
261
  <div class="flex w-1/3 flex-col px-2">
133
262
  <UI.Input
@@ -139,15 +268,100 @@
139
268
  label={{ name: $t('constructor.props.value') }}
140
269
  value={component.properties.value}
141
270
  type="number"
142
- number={{ minNum: 1, maxNum: 2, step: 1 }}
271
+ number={{ minNum: 0, maxNum: component.properties.bitMode ? Math.pow(2, 32) : 1, step: 1 }}
143
272
  onUpdate={(value) => updateProperty('value', value as number, component, onPropertyChange)}
144
273
  />
145
274
  <UI.Switch
146
275
  wrapperClass="bg-blue"
147
276
  label={{ name: $t('constructor.props.disabled') }}
148
- value={component.properties.disabled ? 2 : 1}
149
- onChange={(value) => updateProperty('disabled', value === 2, component, onPropertyChange)}
277
+ value={component.properties.disabled}
278
+ options={[{ id: crypto.randomUUID(), value: 0, class: '' }]}
279
+ onChange={(value) => updateProperty('disabled', value, component, onPropertyChange)}
280
+ />
281
+ <UI.Switch
282
+ wrapperClass="bg-blue"
283
+ label={{ name: $t('constructor.props.bitmode') }}
284
+ value={component.properties.bitMode}
285
+ options={[{ id: crypto.randomUUID(), value: 0, class: '' }]}
286
+ onChange={(value) => {
287
+ updateProperty('bitMode', value, component, onPropertyChange)
288
+ updateProperty('value', 1, component, onPropertyChange)
289
+ }}
150
290
  />
151
291
  </div>
152
292
  </div>
293
+ {#if component.properties.bitMode}
294
+ <hr class="border-gray-400" />
295
+
296
+ <!-- Настройки опций -->
297
+ <div class="space-y-4">
298
+ <div class="m-0 flex items-center justify-center gap-2">
299
+ <h4>{$t('constructor.props.bits.title')}</h4>
300
+ <UI.Button
301
+ wrapperClass="w-8"
302
+ content={{ icon: ButtonAdd }}
303
+ onClick={() => {
304
+ const newOption: ISelectOption = {
305
+ id: crypto.randomUUID(),
306
+ name: `Option ${component.properties?.options.length + 1}`,
307
+ value: component.properties?.options.length,
308
+ class: 'bg-blue',
309
+ }
310
+ const options = [...(component.properties?.options || []), newOption]
311
+ updateProperty('options', options, component, onPropertyChange)
312
+ }}
313
+ />
314
+ </div>
315
+
316
+ {#each component.properties.options || [] as option, index (option.id)}
317
+ <div class="m-0 flex items-end justify-around gap-2 border-gray-400">
318
+ <UI.Input
319
+ label={{ name: $t('constructor.props.optionname') }}
320
+ wrapperClass="!w-3/10"
321
+ value={option.name}
322
+ onUpdate={(value) => {
323
+ const options = [...(component.properties?.options || [])]
324
+ options[index]['name'] = value
325
+ updateProperty('options', options, component, onPropertyChange)
326
+ }}
327
+ />
328
+ <UI.Input
329
+ label={{ name: $t('constructor.props.optionvalue') }}
330
+ wrapperClass="!w-3/10"
331
+ value={option.value}
332
+ type="number"
333
+ number={{ minNum: 0, maxNum: 31, step: 1 }}
334
+ onUpdate={(value) => {
335
+ const options = [...(component.properties?.options || [])]
336
+ options[index]['value'] = value
337
+ updateProperty('options', options, component, onPropertyChange)
338
+ }}
339
+ />
340
+ <UI.Select
341
+ wrapperClass="w-80 h-14.5"
342
+ label={{ name: $t('constructor.props.colors') }}
343
+ type="buttons"
344
+ options={$optionsStore.COLOR_OPTIONS.filter((option) => option.value !== 'bg-max' && option.value !== 'bg-gray')}
345
+ value={$optionsStore.COLOR_OPTIONS.find((c) =>
346
+ (c.value as string).includes(option.class.split(' ').find((cls: string) => cls.startsWith('bg-'))),
347
+ )}
348
+ onUpdate={(option) => {
349
+ const options = [...(component.properties?.options || [])]
350
+ options[index]['class'] = option.value
351
+ updateProperty('options', options, component, onPropertyChange)
352
+ }}
353
+ />
354
+ <UI.Button
355
+ wrapperClass="w-8"
356
+ content={{ icon: ButtonDelete }}
357
+ onClick={() => {
358
+ const options = [...(component.properties?.options || [])]
359
+ options.splice(index, 1)
360
+ updateProperty('options', options, component, onPropertyChange)
361
+ }}
362
+ />
363
+ </div>
364
+ {/each}
365
+ </div>
366
+ {/if}
153
367
  {/if}
@@ -155,7 +155,7 @@
155
155
  })
156
156
  </script>
157
157
 
158
- <div {id} class={twMerge(`bg-blue flex h-full w-full flex-col overflow-hidden`, wrapperClass)}>
158
+ <div id={`${id}-${crypto.randomUUID().slice(0, 6)}`} class={twMerge(`bg-blue flex h-full w-full flex-col overflow-hidden`, wrapperClass)}>
159
159
  {#if label.name}
160
160
  <h5 class={twMerge(`w-full px-4 text-center`, label.class)}>{label.name}</h5>
161
161
  {/if}
@@ -97,8 +97,9 @@
97
97
  />
98
98
  <UI.Switch
99
99
  label={{ name: $t('constructor.props.outline') }}
100
- value={component.properties.outline ? 2 : 1}
101
- onChange={(value) => updateProperty('outline', value === 2, component, onPropertyChange)}
100
+ value={component.properties.outline}
101
+ options={[{ id: crypto.randomUUID(), value: 0, class: '' }]}
102
+ onChange={(value) => updateProperty('outline', value, component, onPropertyChange)}
102
103
  />
103
104
  </div>
104
105
  <div class="flex w-1/3 flex-col px-2">
@@ -168,14 +169,16 @@
168
169
  <UI.Switch
169
170
  wrapperClass="w-2/10"
170
171
  label={{ name: $t('constructor.props.table.columns.sortable') }}
171
- value={column.sortable ? 2 : 1}
172
- onChange={(value) => updateTableHeader(columnIndex, 'sortable', value === 2)}
172
+ options={[{ id: crypto.randomUUID(), value: 0, class: '' }]}
173
+ value={column.sortable}
174
+ onChange={(value) => updateTableHeader(columnIndex, 'sortable', value)}
173
175
  />
174
176
  <UI.Switch
175
177
  wrapperClass="w-2/10"
176
178
  label={{ name: $t('constructor.props.copy') }}
177
- value={column.overflow?.copy ? 2 : 1}
178
- onChange={(value) => updateTableHeader(columnIndex, 'overflow', { copy: value === 2 })}
179
+ options={[{ id: crypto.randomUUID(), value: 0, class: '' }]}
180
+ value={column.overflow?.copy}
181
+ onChange={(value) => updateTableHeader(columnIndex, 'overflow', { copy: value })}
179
182
  />
180
183
  <UI.Button
181
184
  wrapperClass="w-8"
@@ -302,8 +305,9 @@
302
305
  />
303
306
  <UI.Switch
304
307
  label={{ name: $t('constructor.props.outline') }}
305
- value={component.properties.outline ? 2 : 1}
306
- onChange={(value) => updateProperty('outline', value === 2, component, onPropertyChange)}
308
+ value={component.properties.outline}
309
+ options={[{ id: crypto.randomUUID(), value: 0, class: '' }]}
310
+ onChange={(value) => updateProperty('outline', value, component, onPropertyChange)}
307
311
  />
308
312
  </div>
309
313
  </div>
@@ -370,14 +374,16 @@
370
374
  <UI.Switch
371
375
  label={{ name: $t('constructor.props.table.columns.sortable'), class: 'px-0' }}
372
376
  wrapperClass="w-30"
373
- value={column.sortable ? 2 : 1}
374
- onChange={(value) => updateTableHeader(columnIndex, 'sortable', value === 2)}
377
+ options={[{ id: crypto.randomUUID(), value: 0, class: '' }]}
378
+ value={column.sortable}
379
+ onChange={(value) => updateTableHeader(columnIndex, 'sortable', value)}
375
380
  />
376
381
  <UI.Switch
377
382
  label={{ name: $t('constructor.props.copy'), class: 'px-0' }}
378
383
  wrapperClass="w-30"
379
- value={column.overflow?.copy ? 2 : 1}
380
- onChange={(value) => updateTableHeader(columnIndex, 'overflow', { copy: value === 2, truncated: column.overflow?.truncated })}
384
+ options={[{ id: crypto.randomUUID(), value: 0, class: '' }]}
385
+ value={column.overflow?.copy}
386
+ onChange={(value) => updateTableHeader(columnIndex, 'overflow', { copy: value, truncated: column.overflow?.truncated })}
381
387
  />
382
388
  <UI.Button
383
389
  wrapperClass="w-8"
@@ -414,8 +420,9 @@
414
420
  <UI.Switch
415
421
  wrapperClass="w-2/10"
416
422
  label={{ name: $t('constructor.props.table.columns.truncated') }}
417
- value={column.overflow?.truncated ? 2 : 1}
418
- onChange={(value) => updateTableHeader(columnIndex, 'overflow', { truncated: value === 2, copy: column.overflow?.copy })}
423
+ options={[{ id: crypto.randomUUID(), value: 0, class: '' }]}
424
+ value={column.overflow?.truncated}
425
+ onChange={(value) => updateTableHeader(columnIndex, 'overflow', { truncated: value, copy: column.overflow?.copy })}
419
426
  />
420
427
  <div class="relative mt-6 flex w-full gap-2">
421
428
  <UI.Button
@@ -26,7 +26,7 @@
26
26
  let currentTabIndex: number = $state(activeTab)
27
27
  </script>
28
28
 
29
- <div {id} class="w-full rounded-2xl bg-(--back-color)">
29
+ <div id={`${id}-${crypto.randomUUID().slice(0, 6)}`} class="w-full rounded-2xl bg-(--back-color)">
30
30
  <!-- Вкладки -->
31
31
  <div
32
32
  class="{twMerge('bg-blue sticky top-0 z-50 flex h-fit items-center overflow-x-auto rounded-t-2xl px-1', wrapperClass)}
@@ -75,7 +75,7 @@
75
75
  {@render Components(comp, false)}
76
76
  {/each}
77
77
  {:else if children}
78
- {@render children(items[activeTab])}
78
+ {@render children(items[currentTabIndex])}
79
79
  {:else}
80
80
  {@render items[currentTabIndex]?.children?.()}
81
81
  {/if}
@@ -52,9 +52,9 @@
52
52
  const initialWidth = $derived(() => {
53
53
  let width = component.properties.items.find((item: ISelectOption) => item.class?.split(' ').find((cls: string) => cls.startsWith('w-')))
54
54
  if (!width) {
55
- return 1
56
- } else if (width.class.includes('w-auto')) return 1
57
- else return 2
55
+ return 0
56
+ } else if (width.class.includes('w-auto')) return 0
57
+ else return 1
58
58
  })
59
59
  </script>
60
60
 
@@ -107,10 +107,11 @@
107
107
  captionRight: $t('constructor.props.equal'),
108
108
  }}
109
109
  value={initialWidth()}
110
+ options={[{ id: crypto.randomUUID(), value: 0, class: '' }]}
110
111
  onChange={(value) => {
111
112
  component.properties.items.forEach((_item: any, index: number) => {
112
113
  const items = [...(component.properties?.items || [])]
113
- items[index]['class'] = twMerge(items[index].class, value === 2 ? `w-[${(1 / items.length) * 100}%]` : 'w-auto')
114
+ items[index]['class'] = twMerge(items[index].class, value ? `w-[${(1 / items.length) * 100}%]` : 'w-auto')
114
115
  updateProperty('items', items, component, onPropertyChange)
115
116
  })
116
117
  }}
@@ -132,7 +133,7 @@
132
133
  }
133
134
  const items = [...(component.properties?.items || []), newItem]
134
135
  items.forEach((_item: any, index: number) => {
135
- items[index]['class'] = twMerge(items[index].class, initialWidth() === 2 ? `w-[${(1 / items.length) * 100}%]` : 'w-auto')
136
+ items[index]['class'] = twMerge(items[index].class, initialWidth() ? `w-[${(1 / items.length) * 100}%]` : 'w-auto')
136
137
  updateProperty('items', items, component, onPropertyChange)
137
138
  })
138
139
  }}
@@ -176,7 +177,7 @@
176
177
  const items = [...(component.properties?.items || [])]
177
178
  items.splice(index, 1)
178
179
  items.forEach((_item: any, index: number) => {
179
- items[index]['class'] = twMerge(items[index].class, initialWidth() === 2 ? `w-[${(1 / items.length) * 100}%]` : 'w-auto')
180
+ items[index]['class'] = twMerge(items[index].class, initialWidth() ? `w-[${(1 / items.length) * 100}%]` : 'w-auto')
180
181
  updateProperty('items', items, component, onPropertyChange)
181
182
  })
182
183
  updateProperty('items', items, component, onPropertyChange)
@@ -289,6 +290,7 @@
289
290
  captionRight: $t('constructor.props.equal'),
290
291
  }}
291
292
  value={initialWidth()}
293
+ options={[{ id: crypto.randomUUID(), value: 0, class: '' }]}
292
294
  onChange={(value) => {
293
295
  if (value === 2) {
294
296
  component.properties.items.forEach((_item: any, index: number) => {
@@ -319,7 +321,7 @@
319
321
  let tabWidth = Math.max(...Array.from(document.body.querySelectorAll('.tab')).map((item) => (item as HTMLElement).offsetWidth))
320
322
  const newItem: { name: string; icon: string; class: string } = {
321
323
  name: `Tab ${component.properties?.items.length + 1}`,
322
- class: `w-${initialWidth() === 2 ? `[${tabWidth}px]` : 'auto'} text-${initialColor?.value.slice(3)}-500 ${initialPosition?.value}`,
324
+ class: `w-${initialWidth() ? `[${tabWidth}px]` : 'auto'} text-${initialColor?.value.slice(3)}-500 ${initialPosition?.value}`,
323
325
  icon: '',
324
326
  }
325
327
  const items = [...(component.properties?.items || []), newItem]
@@ -13,7 +13,10 @@
13
13
  } as const
14
14
  </script>
15
15
 
16
- <div {id} class={twMerge(`relative flex w-full flex-col items-center ${background ? 'rounded-2xl bg-(--back-color) px-6 py-2' : ''}`, wrapperClass)}>
16
+ <div
17
+ id={`${id}-${crypto.randomUUID().slice(0, 6)}`}
18
+ class={twMerge(`relative flex w-full flex-col items-center ${background ? 'rounded-2xl bg-(--back-color) px-6 py-2' : ''}`, wrapperClass)}
19
+ >
17
20
  <p class={twMerge(`w-full text-center ${textSize[content.size ?? 'base']}`, content.class)}>
18
21
  {content.name}
19
22
  </p>
@@ -79,30 +79,28 @@
79
79
  <div class="flex w-1/3 flex-col px-2">
80
80
  <UI.Switch
81
81
  label={{ name: $t('constructor.props.bold') }}
82
- value={initialBold ? 2 : 1}
82
+ value={initialBold}
83
+ options={[{ id: crypto.randomUUID(), value: 0, class: '' }]}
83
84
  onChange={(value) =>
84
85
  updateProperty(
85
86
  'content.class',
86
- `${component.properties.content.class} ${value === 2 ? 'font-bold' : 'font-normal'}`,
87
+ `${component.properties.content.class} ${value ? 'font-bold' : 'font-normal'}`,
87
88
  component,
88
89
  onPropertyChange,
89
90
  )}
90
91
  />
91
92
  <UI.Switch
92
93
  label={{ name: $t('constructor.props.italic') }}
93
- value={initialItalic ? 2 : 1}
94
+ value={initialItalic}
95
+ options={[{ id: crypto.randomUUID(), value: 0, class: '' }]}
94
96
  onChange={(value) =>
95
- updateProperty(
96
- 'content.class',
97
- `${component.properties.content.class} ${value === 2 ? 'italic' : 'not-italic'}`,
98
- component,
99
- onPropertyChange,
100
- )}
97
+ updateProperty('content.class', `${component.properties.content.class} ${value ? 'italic' : 'not-italic'}`, component, onPropertyChange)}
101
98
  />
102
99
  <UI.Switch
103
100
  label={{ name: $t('constructor.props.background') }}
104
- value={component.properties.background ? 2 : 1}
105
- onChange={(value) => updateProperty('background', value === 2, component, onPropertyChange)}
101
+ value={component.properties.background}
102
+ options={[{ id: crypto.randomUUID(), value: 0, class: '' }]}
103
+ onChange={(value) => updateProperty('background', value, component, onPropertyChange)}
106
104
  />
107
105
  </div>
108
106
  </div>
@@ -152,30 +150,33 @@
152
150
  <div class="flex w-1/3 flex-col px-2">
153
151
  <UI.Switch
154
152
  label={{ name: $t('constructor.props.bold') }}
155
- value={initialBold ? 2 : 1}
153
+ value={initialBold}
154
+ options={[{ id: crypto.randomUUID(), value: 0, class: '' }]}
156
155
  onChange={(value) =>
157
156
  updateProperty(
158
157
  'content.class',
159
- twMerge(`${component.properties.content.class} ${value === 2 ? 'font-bold' : 'font-normal'}`),
158
+ twMerge(`${component.properties.content.class} ${value ? 'font-bold' : 'font-normal'}`),
160
159
  component,
161
160
  onPropertyChange,
162
161
  )}
163
162
  />
164
163
  <UI.Switch
165
164
  label={{ name: $t('constructor.props.italic') }}
166
- value={initialItalic ? 2 : 1}
165
+ value={initialItalic}
166
+ options={[{ id: crypto.randomUUID(), value: 0, class: '' }]}
167
167
  onChange={(value) =>
168
168
  updateProperty(
169
169
  'content.class',
170
- twMerge(`${component.properties.content.class} ${value === 2 ? 'italic' : 'not-italic'}`),
170
+ twMerge(`${component.properties.content.class} ${value ? 'italic' : 'not-italic'}`),
171
171
  component,
172
172
  onPropertyChange,
173
173
  )}
174
174
  />
175
175
  <UI.Switch
176
176
  label={{ name: $t('constructor.props.background') }}
177
- value={component.properties.background ? 2 : 1}
178
- onChange={(value) => updateProperty('background', value === 2, component, onPropertyChange)}
177
+ value={component.properties.background}
178
+ options={[{ id: crypto.randomUUID(), value: 0, class: '' }]}
179
+ onChange={(value) => updateProperty('background', value, component, onPropertyChange)}
179
180
  />
180
181
  </div>
181
182
  </div>
@@ -37,6 +37,9 @@ const translations = {
37
37
  'constructor.props.type.contain': 'Полный',
38
38
  'constructor.props.type.square': 'Квадрат',
39
39
  'constructor.props.type.circle': 'Круг',
40
+ 'constructor.props.type.horizontal': 'Горизонтально',
41
+ 'constructor.props.type.vertical': 'Вертикально',
42
+ 'constructor.props.type.checkbox': 'Галочка',
40
43
  /* Общие для редактора свойств */
41
44
  'constructor.props.id': 'Идентификатор',
42
45
  'constructor.props.label': 'Текст надписи',
@@ -95,6 +98,7 @@ const translations = {
95
98
  'constructor.props.widthMode': 'Ширина кнопок',
96
99
  'constructor.props.graphdata.title': 'Начальные данные ',
97
100
  'constructor.props.options.title': 'Опции компонента',
101
+ 'constructor.props.bits.title': 'Биты',
98
102
  'constructor.props.tabs.title': 'Вкладки меню',
99
103
  'constructor.props.valuetype': 'Тип значения',
100
104
  'constructor.props.action': 'Действие при переключении',
@@ -114,6 +118,7 @@ const translations = {
114
118
  'constructor.props.size.width': 'Ширина сетки',
115
119
  'constructor.props.icon.text.position': 'Положение иконки',
116
120
  'constructor.props.equal': 'Равные',
121
+ 'constructor.props.bitmode': 'Битовый режим',
117
122
  'constructor.props.table.columns': 'Колонки таблицы',
118
123
  'constructor.props.table.columns.key': 'Ключ',
119
124
  'constructor.props.table.columns.label': 'Название колонки',
package/dist/options.d.ts CHANGED
@@ -95,6 +95,11 @@ export declare const optionsStore: import("svelte/store").Readable<{
95
95
  value: string;
96
96
  name: string;
97
97
  }[];
98
+ SWITCH_OPTIONS: {
99
+ id: string;
100
+ value: string;
101
+ name: string;
102
+ }[];
98
103
  INFO_SIDE_OPTIONS: {
99
104
  id: string;
100
105
  value: string;
package/dist/options.js CHANGED
@@ -104,6 +104,11 @@ export const optionsStore = derived(t, ($t) => {
104
104
  { id: id(), value: 'cover', name: $t('constructor.props.type.cover') },
105
105
  { id: id(), value: 'contain', name: $t('constructor.props.type.contain') },
106
106
  ],
107
+ SWITCH_OPTIONS: [
108
+ { id: id(), value: 'horizontal', name: $t('constructor.props.type.horizontal') },
109
+ { id: id(), value: 'vertical', name: $t('constructor.props.type.vertical') },
110
+ { id: id(), value: 'checkbox', name: $t('constructor.props.type.checkbox') },
111
+ ],
107
112
  INFO_SIDE_OPTIONS: [
108
113
  { id: id(), value: 'top', name: $t('constructor.props.info.top') },
109
114
  { id: id(), value: 'bottom', name: $t('constructor.props.info.bottom') },
package/dist/types.d.ts CHANGED
@@ -106,6 +106,7 @@ export interface ISelectProps<T = unknown> {
106
106
  type?: 'select' | 'buttons' | 'input';
107
107
  value?: ISelectOption<T> | null;
108
108
  options?: ISelectOption<T>[];
109
+ bitMode?: boolean;
109
110
  eventHandler?: IUIComponentHandler;
110
111
  onUpdate?: (value: ISelectOption<T>) => void;
111
112
  }
@@ -127,6 +128,8 @@ export interface ISwitchProps {
127
128
  captionLeft?: string;
128
129
  captionRight?: string;
129
130
  };
131
+ options?: ISelectOption<number>[];
132
+ bitMode?: boolean;
130
133
  type?: 'horizontal' | 'vertical' | 'checkbox';
131
134
  value?: number;
132
135
  eventHandler?: IUIComponentHandler;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "poe-svelte-ui-lib",
3
- "version": "1.2.20",
3
+ "version": "1.2.22",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -48,7 +48,7 @@
48
48
  "@sveltejs/vite-plugin-svelte": "^6.2.1",
49
49
  "@types/node": "^24.10.1",
50
50
  "publint": "^0.3.15",
51
- "svelte": "^5.43.6",
51
+ "svelte": "^5.43.8",
52
52
  "svelte-preprocess": "^6.0.3",
53
53
  "vite": "^7.2.2",
54
54
  "vite-plugin-compression": "^0.5.1"