poe-svelte-ui-lib 1.2.21 → 1.2.23

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.
@@ -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,82 @@
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 shadow-md
78
+ {checkedOptions[index] ? 'border-(--bg-color)' : 'border-(--bg-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 border-(--bg-color) transition-all duration-250
91
+ {checkedOptions[index] ? 'bg-(--bg-color)' : 'bg-(--back-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 transition-all duration-250
97
+ {checkedOptions[index] ? 'bg-(--back-color)' : 'bg-(--bg-color)'}
98
+ {option.disabled ? 'opacity-60' : 'cursor-pointer'}"
99
+ style="width: {`calc(${height} * 0.8)`}; height: {`calc(${height} * 0.8)`}; margin: 0 {`calc(${height} * 0.1)`}; transform: {checkedOptions[
100
+ index
101
+ ]
102
+ ? `${type === 'horizontal' ? `translateX(calc(${height}))` : `translateY(calc(-${height}/2))`}`
103
+ : `${type === 'horizontal' ? 'translateX(0)' : `translateY(calc(${height}/2))`}`};"
104
+ ></span>
105
+ </span>
106
+ </label>
66
107
 
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}
108
+ {#if type === 'horizontal' && label.captionRight}
109
+ <button
110
+ class="ml-2 {option.disabled ? 'opacity-60' : 'cursor-pointer'}"
111
+ style="width: {maxCaptionWidth}; text-align: start;"
112
+ onclick={() => handleCaptionClick(1)}>{label.captionRight}</button
113
+ >
114
+ {/if}
115
+ </div>
116
+ </div>
117
+ {/each}
100
118
  </div>
101
119
  </div>
102
120
  {:else}
103
121
  <div class={twMerge('bg-blue m-1 flex items-center justify-center gap-2', wrapperClass)}>
104
122
  <input
105
- {id}
123
+ id={ID}
106
124
  type="checkbox"
107
- bind:checked
108
- {disabled}
125
+ checked={checkedOptions[0]}
126
+ disabled={localOptions[0].disabled}
109
127
  class="
110
128
  relative size-8 cursor-pointer appearance-none rounded-2xl border border-(--bg-color)
111
129
  bg-white transition duration-300 after:origin-bottom-left after:opacity-0
112
130
  checked:border-(--bg-color)
113
- checked:bg-(--bg-color) checked:after:absolute checked:after:left-[5.5px]
131
+ checked:bg-(--bg-color) checked:after:absolute checked:after:-top-px checked:after:left-[5px]
114
132
  checked:after:h-[13.5px] checked:after:w-[7.5px] checked:after:rotate-43
115
133
  checked:after:border-2 checked:after:border-t-0
116
134
  checked:after:border-l-0 checked:after:border-solid
@@ -118,9 +136,9 @@
118
136
  checked:after:content-[''] hover:shadow-md
119
137
  disabled:cursor-not-allowed disabled:opacity-70
120
138
  "
121
- onchange={handleToggle}
139
+ onchange={() => handleToggle(0)}
122
140
  />
123
- <label for={id} class={twMerge("{disabled ? 'cursor-not-allowed opacity-70' : 'cursor-pointer'} ml-1 select-none", label.class)}>
141
+ <label for={ID} class={twMerge("{disabled ? 'cursor-not-allowed opacity-70' : 'cursor-pointer'} ml-1 select-none", label.class)}>
124
142
  {label.name}
125
143
  </label>
126
144
  </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,162 @@
47
49
  updateProperty('eventHandler.Argument', option.value as string, component, onPropertyChange)
48
50
  }}
49
51
  />
50
- </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)}
52
+ <UI.Select
53
+ wrapperClass="!h-14"
54
+ label={{ name: $t('constructor.props.type') }}
55
+ disabled={component.properties.bitMode}
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)}
67
60
  />
68
61
  </div>
62
+ {#if !component.properties.bitMode}
63
+ <div class="flex w-1/3 flex-col px-2">
64
+ <UI.Input
65
+ label={{ name: $t('constructor.props.caption.left') }}
66
+ value={component.properties.label.captionLeft}
67
+ onUpdate={(value) => updateProperty('label.captionLeft', value as string, component, onPropertyChange)}
68
+ />
69
+ <UI.Input
70
+ label={{ name: $t('constructor.props.caption.right') }}
71
+ value={component.properties.label.captionRight}
72
+ onUpdate={(value) => updateProperty('label.captionRight', value as string, component, onPropertyChange)}
73
+ />
74
+
75
+ <UI.Switch
76
+ wrapperClass="bg-blue"
77
+ label={{ name: $t('constructor.props.disabled') }}
78
+ value={component.properties.options[0].disabled}
79
+ options={[{ id: crypto.randomUUID(), value: 0, class: '' }]}
80
+ onChange={(value) => {
81
+ const options = [...(component.properties?.options || [])]
82
+ options[0]['disabled'] = value
83
+ updateProperty('options', options, component, onPropertyChange)
84
+ }}
85
+ />
86
+ </div>
87
+ {/if}
69
88
  <div class="flex w-1/3 flex-col px-2">
70
89
  <UI.Input
71
90
  label={{ name: $t('constructor.props.label') }}
72
91
  value={component.properties.label.name}
73
92
  onUpdate={(value) => updateProperty('label.name', value as string, component, onPropertyChange)}
74
93
  />
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)}
94
+ {#if !component.properties.bitMode}
95
+ <UI.Select
96
+ wrapperClass="!h-14"
97
+ label={{ name: $t('constructor.props.colors') }}
98
+ type="buttons"
99
+ options={$optionsStore.COLOR_OPTIONS.filter((option) => option.value !== 'bg-max' && option.value !== 'bg-gray')}
100
+ value={$optionsStore.COLOR_OPTIONS.find((c) =>
101
+ (c.value as string).includes(component.properties.options[0].class.split(' ').find((cls: string) => cls.startsWith('bg-'))),
102
+ )}
103
+ onUpdate={(option) => {
104
+ const options = [...(component.properties?.options || [])]
105
+ options[0]['class'] = option.value
106
+ updateProperty('options', options, component, onPropertyChange)
107
+ }}
108
+ />
109
+ {/if}
110
+ <UI.Switch
111
+ wrapperClass="bg-blue"
112
+ label={{ name: $t('constructor.props.bitmode') }}
113
+ value={component.properties.bitMode}
114
+ options={[{ id: crypto.randomUUID(), value: 0, class: '' }]}
115
+ onChange={(value) => {
116
+ updateProperty('bitMode', value, component, onPropertyChange)
117
+ if (!component.properties.bitMode) updateProperty('value', 1, component, onPropertyChange)
118
+ if (component.properties.bitMode) updateProperty('type', 'vertical', component, onPropertyChange)
119
+ }}
82
120
  />
83
121
  </div>
84
122
  </div>
123
+ {#if component.properties.bitMode}
124
+ <hr class="border-gray-400" />
125
+
126
+ <!-- Настройки опций -->
127
+ <div class="space-y-4">
128
+ <div class="m-0 flex items-center justify-center gap-2">
129
+ <h4>{$t('constructor.props.bits.title')}</h4>
130
+ <UI.Button
131
+ wrapperClass="w-8"
132
+ content={{ icon: ButtonAdd }}
133
+ onClick={() => {
134
+ const newOption: ISelectOption = {
135
+ id: crypto.randomUUID(),
136
+ name: ``,
137
+ value: component.properties?.options.length,
138
+ class: 'bg-blue',
139
+ }
140
+ const options = [...(component.properties?.options || []), newOption]
141
+ updateProperty('options', options, component, onPropertyChange)
142
+ }}
143
+ />
144
+ </div>
145
+
146
+ {#each component.properties.options || [] as option, index (option.id)}
147
+ <div class="m-0 flex items-end justify-around gap-2 border-gray-400">
148
+ <UI.Input
149
+ label={{ name: $t('constructor.props.optionname') }}
150
+ wrapperClass="!w-3/10"
151
+ value={option.name}
152
+ onUpdate={(value) => {
153
+ const options = [...(component.properties?.options || [])]
154
+ options[index]['name'] = value
155
+ updateProperty('options', options, component, onPropertyChange)
156
+ }}
157
+ />
158
+ <UI.Input
159
+ label={{ name: $t('constructor.props.optionposition') }}
160
+ wrapperClass="!w-3/10"
161
+ value={option.value}
162
+ type="number"
163
+ number={{ minNum: 0, maxNum: 31, step: 1 }}
164
+ onUpdate={(value) => {
165
+ const options = [...(component.properties?.options || [])]
166
+ options[index]['value'] = value
167
+ updateProperty('options', options, component, onPropertyChange)
168
+ }}
169
+ />
170
+ <UI.Select
171
+ wrapperClass="w-80 h-14.5"
172
+ label={{ name: $t('constructor.props.colors') }}
173
+ type="buttons"
174
+ options={$optionsStore.COLOR_OPTIONS.filter((option) => option.value !== 'bg-max' && option.value !== 'bg-gray')}
175
+ value={$optionsStore.COLOR_OPTIONS.find((c) =>
176
+ (c.value as string).includes(option.class.split(' ').find((cls: string) => cls.startsWith('bg-'))),
177
+ )}
178
+ onUpdate={(option) => {
179
+ const options = [...(component.properties?.options || [])]
180
+ options[index]['class'] = option.value
181
+ updateProperty('options', options, component, onPropertyChange)
182
+ }}
183
+ />
184
+ <UI.Switch
185
+ wrapperClass=" w-1/10 bg-blue"
186
+ label={{ name: $t('constructor.props.disabled') }}
187
+ value={option.disabled}
188
+ options={[{ id: crypto.randomUUID(), value: 0, class: '' }]}
189
+ onChange={(value) => {
190
+ const options = [...(component.properties?.options || [])]
191
+ options[index]['disabled'] = value
192
+ updateProperty('options', options, component, onPropertyChange)
193
+ }}
194
+ />
195
+ <UI.Button
196
+ wrapperClass="w-8"
197
+ content={{ icon: ButtonDelete }}
198
+ onClick={() => {
199
+ const options = [...(component.properties?.options || [])]
200
+ options.splice(index, 1)
201
+ updateProperty('options', options, component, onPropertyChange)
202
+ }}
203
+ />
204
+ </div>
205
+ {/each}
206
+ </div>
207
+ {/if}
85
208
  {:else}
86
209
  <div class="relative flex flex-row items-start justify-center">
87
210
  <!-- Сообщение для отправки в ws по нажатию кнопки -->
@@ -101,7 +224,7 @@
101
224
  label={{ name: $t('constructor.props.colors') }}
102
225
  type="buttons"
103
226
  options={$optionsStore.COLOR_OPTIONS.filter((option) => option.value !== 'bg-max' && option.value !== 'bg-gray')}
104
- value={initialColor}
227
+ value={component.properties.options[0].class.split(' ').find((cls: string) => cls.startsWith('bg-'))}
105
228
  onUpdate={(option) => {
106
229
  updateProperty('wrapperClass', twMerge(component.properties.wrapperClass, option.value), component, onPropertyChange)
107
230
  const options = [...(component.properties?.options || [])]
@@ -128,6 +251,14 @@
128
251
  value={component.properties.label.captionRight}
129
252
  onUpdate={(value) => updateProperty('label.captionRight', value as string, component, onPropertyChange)}
130
253
  />
254
+ <UI.Select
255
+ wrapperClass="!h-14"
256
+ label={{ name: $t('constructor.props.type') }}
257
+ type="buttons"
258
+ options={$optionsStore.SWITCH_OPTIONS}
259
+ value={$optionsStore.SWITCH_OPTIONS.find((option) => option.value == component.properties.type)}
260
+ onUpdate={(option) => updateProperty('type', option.value as string, component, onPropertyChange)}
261
+ />
131
262
  </div>
132
263
  <div class="flex w-1/3 flex-col px-2">
133
264
  <UI.Input
@@ -139,15 +270,101 @@
139
270
  label={{ name: $t('constructor.props.value') }}
140
271
  value={component.properties.value}
141
272
  type="number"
142
- number={{ minNum: 1, maxNum: 2, step: 1 }}
273
+ number={{ minNum: 0, maxNum: component.properties.bitMode ? Math.pow(2, 32) : 1, step: 1 }}
143
274
  onUpdate={(value) => updateProperty('value', value as number, component, onPropertyChange)}
144
275
  />
145
276
  <UI.Switch
146
277
  wrapperClass="bg-blue"
147
278
  label={{ name: $t('constructor.props.disabled') }}
148
- value={component.properties.disabled ? 2 : 1}
149
- onChange={(value) => updateProperty('disabled', value === 2, component, onPropertyChange)}
279
+ value={component.properties.disabled}
280
+ options={[{ id: crypto.randomUUID(), value: 0, class: '' }]}
281
+ onChange={(value) => updateProperty('disabled', value, component, onPropertyChange)}
282
+ />
283
+ <UI.Switch
284
+ wrapperClass="bg-blue"
285
+ label={{ name: $t('constructor.props.bitmode') }}
286
+ value={component.properties.bitMode}
287
+ options={[{ id: crypto.randomUUID(), value: 0, class: '' }]}
288
+ onChange={(value) => {
289
+ updateProperty('bitMode', value, component, onPropertyChange)
290
+ if (!component.properties.bitMode) updateProperty('value', 1, component, onPropertyChange)
291
+ if (component.properties.bitMode) updateProperty('type', 'vertical', component, onPropertyChange)
292
+ }}
150
293
  />
151
294
  </div>
152
295
  </div>
296
+ {#if component.properties.bitMode}
297
+ <hr class="border-gray-400" />
298
+
299
+ <!-- Настройки опций -->
300
+ <div class="space-y-4">
301
+ <div class="m-0 flex items-center justify-center gap-2">
302
+ <h4>{$t('constructor.props.bits.title')}</h4>
303
+ <UI.Button
304
+ wrapperClass="w-8"
305
+ content={{ icon: ButtonAdd }}
306
+ onClick={() => {
307
+ const newOption: ISelectOption = {
308
+ id: crypto.randomUUID(),
309
+ name: `Option ${component.properties?.options.length + 1}`,
310
+ value: component.properties?.options.length,
311
+ class: 'bg-blue',
312
+ }
313
+ const options = [...(component.properties?.options || []), newOption]
314
+ updateProperty('options', options, component, onPropertyChange)
315
+ }}
316
+ />
317
+ </div>
318
+
319
+ {#each component.properties.options || [] as option, index (option.id)}
320
+ <div class="m-0 flex items-end justify-around gap-2 border-gray-400">
321
+ <UI.Input
322
+ label={{ name: $t('constructor.props.optionname') }}
323
+ wrapperClass="!w-3/10"
324
+ value={option.name}
325
+ onUpdate={(value) => {
326
+ const options = [...(component.properties?.options || [])]
327
+ options[index]['name'] = value
328
+ updateProperty('options', options, component, onPropertyChange)
329
+ }}
330
+ />
331
+ <UI.Input
332
+ label={{ name: $t('constructor.props.optionvalue') }}
333
+ wrapperClass="!w-3/10"
334
+ value={option.value}
335
+ type="number"
336
+ number={{ minNum: 0, maxNum: 31, step: 1 }}
337
+ onUpdate={(value) => {
338
+ const options = [...(component.properties?.options || [])]
339
+ options[index]['value'] = value
340
+ updateProperty('options', options, component, onPropertyChange)
341
+ }}
342
+ />
343
+ <UI.Select
344
+ wrapperClass="w-80 h-14.5"
345
+ label={{ name: $t('constructor.props.colors') }}
346
+ type="buttons"
347
+ options={$optionsStore.COLOR_OPTIONS.filter((option) => option.value !== 'bg-max' && option.value !== 'bg-gray')}
348
+ value={$optionsStore.COLOR_OPTIONS.find((c) =>
349
+ (c.value as string).includes(option.class.split(' ').find((cls: string) => cls.startsWith('bg-'))),
350
+ )}
351
+ onUpdate={(option) => {
352
+ const options = [...(component.properties?.options || [])]
353
+ options[index]['class'] = option.value
354
+ updateProperty('options', options, component, onPropertyChange)
355
+ }}
356
+ />
357
+ <UI.Button
358
+ wrapperClass="w-8"
359
+ content={{ icon: ButtonDelete }}
360
+ onClick={() => {
361
+ const options = [...(component.properties?.options || [])]
362
+ options.splice(index, 1)
363
+ updateProperty('options', options, component, onPropertyChange)
364
+ }}
365
+ />
366
+ </div>
367
+ {/each}
368
+ </div>
369
+ {/if}
153
370
  {/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)}