poe-svelte-ui-lib 1.2.25 → 1.2.26

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.
@@ -46,10 +46,10 @@
46
46
  </script>
47
47
 
48
48
  {#if forConstructor}
49
- <div class="flex items-center justify-center gap-8">
49
+ <div class="flex items-start justify-center gap-8">
50
50
  <div class="flex w-1/3 flex-col items-center px-2">
51
51
  <UI.Select
52
- label={{ name: $t('constructor.props.icon.access') }}
52
+ label={{ name: $t('constructor.props.access') }}
53
53
  type="buttons"
54
54
  options={$optionsStore.ACCESS_OPTION}
55
55
  value={$optionsStore.ACCESS_OPTION.find((o) => o.value === component.access)}
@@ -137,13 +137,20 @@
137
137
  </div>
138
138
  </div>
139
139
  {:else}
140
- <div class="flex items-center justify-center gap-8">
140
+ <div class="flex items-start justify-center gap-8">
141
141
  <div class="flex w-1/3 flex-col items-center px-2">
142
142
  <UI.Input
143
143
  label={{ name: $t('constructor.props.id') }}
144
144
  value={component.properties.id}
145
145
  onUpdate={(value) => updateProperty('id', value as string, component, onPropertyChange)}
146
146
  />
147
+ <UI.Select
148
+ label={{ name: $t('constructor.props.access') }}
149
+ type="buttons"
150
+ options={$optionsStore.ACCESS_OPTION}
151
+ value={$optionsStore.ACCESS_OPTION.find((o) => o.value === component.access)}
152
+ onUpdate={(option) => onPropertyChange(null, null, option.value)}
153
+ />
147
154
  <UI.Select
148
155
  label={{ name: $t('constructor.props.type') }}
149
156
  type="buttons"
@@ -175,7 +182,7 @@
175
182
  onChange={(value) => updateProperty('isOpen', value, component, onPropertyChange)}
176
183
  />
177
184
  </div>
178
- <div class="flex w-1/3 flex-col items-center px-2">
185
+ <div class="flex w-1/3 flex-col px-2">
179
186
  <UI.Input
180
187
  label={{ name: $t('constructor.props.wrapperclass') }}
181
188
  value={component.properties.wrapperClass}
@@ -76,7 +76,8 @@
76
76
  help={{ info: $t('constructor.props.argument.info'), autocomplete: 'on', regExp: /^[a-zA-Z0-9\-_]{0,32}$/ }}
77
77
  onUpdate={(value) => updateProperty('eventHandler.Argument', value as string, component, onPropertyChange)}
78
78
  />
79
-
79
+ </div>
80
+ <div class="flex w-1/3 flex-col items-center px-2">
80
81
  {#if (component.properties.eventHandler.Argument !== 'Save' && component.properties.eventHandler.Argument !== 'NoSave') || Header.value === 'SET'}
81
82
  <UI.Input
82
83
  label={{ name: $t('constructor.props.value') }}
@@ -97,15 +98,15 @@
97
98
  updateProperty('eventHandler.Variables', parts, component, onPropertyChange)
98
99
  }}
99
100
  />
100
- </div>
101
- <div class="flex w-1/3 flex-col px-2">
102
101
  <UI.Select
103
- label={{ name: $t('constructor.props.icon.access') }}
102
+ label={{ name: $t('constructor.props.access') }}
104
103
  type="buttons"
105
104
  options={$optionsStore.ACCESS_OPTION}
106
- value={$optionsStore.ACCESS_OPTION.find((o) => o.value === component.properties.access)}
107
- onUpdate={(option) => updateProperty('acces', option.value as string, component, onPropertyChange)}
105
+ value={$optionsStore.ACCESS_OPTION.find((o) => o.value === component.access)}
106
+ onUpdate={(option) => onPropertyChange(null, null, option.value)}
108
107
  />
108
+ </div>
109
+ <div class="flex w-1/3 flex-col items-center px-2">
109
110
  <UI.Input
110
111
  label={{ name: $t('constructor.props.name') }}
111
112
  value={component.properties.content.name}
@@ -139,6 +140,13 @@
139
140
  value={component.properties.id}
140
141
  onUpdate={(value) => updateProperty('id', value as string, component, onPropertyChange)}
141
142
  />
143
+ <UI.Select
144
+ label={{ name: $t('constructor.props.access') }}
145
+ type="buttons"
146
+ options={$optionsStore.ACCESS_OPTION}
147
+ value={$optionsStore.ACCESS_OPTION.find((o) => o.value === component.access)}
148
+ onUpdate={(option) => onPropertyChange(null, null, option.value)}
149
+ />
142
150
  <UI.Input
143
151
  label={{ name: $t('constructor.props.wrapperclass') }}
144
152
  value={component.properties.wrapperClass}
@@ -35,8 +35,9 @@
35
35
  options={VARIABLE_OPTIONS}
36
36
  value={VARIABLE_OPTIONS.find((opt) => opt.value === component.properties.id)}
37
37
  onUpdate={(value) => {
38
- updateProperty('id', value.value as string, component, onPropertyChange, value.name?.split('—')[1].trim())
38
+ updateProperty('id', value.value as string, component, onPropertyChange)
39
39
  updateProperty('eventHandler.Variables', value.value as string, component, onPropertyChange)
40
+ onPropertyChange(null, value.name?.split('—')[1].trim(), null)
40
41
  }}
41
42
  />
42
43
  <UI.Select
@@ -51,11 +52,11 @@
51
52
  </div>
52
53
  <div class="flex w-1/3 flex-col items-center px-2">
53
54
  <UI.Select
54
- label={{ name: $t('constructor.props.icon.access') }}
55
+ label={{ name: $t('constructor.props.access') }}
55
56
  type="buttons"
56
57
  options={$optionsStore.ACCESS_OPTION}
57
- value={$optionsStore.ACCESS_OPTION.find((o) => o.value === component.properties.access)}
58
- onUpdate={(option) => updateProperty('acces', option.value as string, component, onPropertyChange)}
58
+ value={$optionsStore.ACCESS_OPTION.find((o) => o.value === component.access)}
59
+ onUpdate={(option) => onPropertyChange(null, null, option.value)}
59
60
  />
60
61
  </div>
61
62
  <div class="flex w-1/3 flex-col px-2">
@@ -82,10 +83,12 @@
82
83
  value={component.properties.id}
83
84
  onUpdate={(value) => updateProperty('id', value as string, component, onPropertyChange)}
84
85
  />
85
- <UI.Input
86
- label={{ name: $t('constructor.props.wrapperclass') }}
87
- value={component.properties.wrapperClass}
88
- onUpdate={(value) => updateProperty('wrapperClass', value as string, component, onPropertyChange)}
86
+ <UI.Select
87
+ label={{ name: $t('constructor.props.access') }}
88
+ type="buttons"
89
+ options={$optionsStore.ACCESS_OPTION}
90
+ value={$optionsStore.ACCESS_OPTION.find((o) => o.value === component.access)}
91
+ onUpdate={(option) => onPropertyChange(null, null, option.value)}
89
92
  />
90
93
  </div>
91
94
  <div class="flex w-1/3 flex-col px-2">
@@ -101,6 +104,11 @@
101
104
  />
102
105
  </div>
103
106
  <div class="flex w-1/3 flex-col px-2">
107
+ <UI.Input
108
+ label={{ name: $t('constructor.props.wrapperclass') }}
109
+ value={component.properties.wrapperClass}
110
+ onUpdate={(value) => updateProperty('wrapperClass', value as string, component, onPropertyChange)}
111
+ />
104
112
  <UI.TextField content={{ name: $t('constructor.props.defaultcolor'), class: 'font-bold' }} />
105
113
  <div class="flex items-center gap-3">
106
114
  <UI.TextField wrapperClass="w-4" content={{ name: 'R', class: 'font-bold' }} />
@@ -25,6 +25,7 @@
25
25
  onChange = () => {},
26
26
  }: IFileInputProps = $props()
27
27
 
28
+ let ID = `${id}-${crypto.randomUUID().slice(0, 6)}`
28
29
  let selectedFile = $state<File | null>(null)
29
30
  let previewUrl = $derived(currentImage ? (currentImage.startsWith('data:') ? currentImage : `data:image/png;base64,${currentImage}`) : null)
30
31
 
@@ -44,7 +45,7 @@
44
45
  }
45
46
 
46
47
  const triggerFileInput = () => {
47
- const input = document.getElementById(id)
48
+ const input = document.getElementById(ID)
48
49
  input?.click()
49
50
  }
50
51
  </script>
@@ -77,19 +78,12 @@
77
78
  <span class="text-sm text-gray-500">Image</span>
78
79
  {/if}
79
80
  </button>
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
+ <input id={ID} type="file" class="absolute -z-10 h-0 w-0 overflow-hidden opacity-0" {accept} {disabled} onchange={handleFileChange} />
88
82
  </div>
89
83
  {:else}
90
84
  <label class="relative inline-block w-full">
91
85
  <input
92
- id={`${id}-${crypto.randomUUID().slice(0, 6)}`}
86
+ id={ID}
93
87
  type="file"
94
88
  class={`h-8.5 w-full rounded-2xl bg-(--back-color) font-semibold shadow-sm transition duration-250 hover:shadow-md
95
89
  ${disabled ? 'cursor-not-allowed opacity-50' : 'cursor-pointer'} invalid:shadow-[0_0_6px(--red-color) file:h-full file:w-1/3
@@ -27,8 +27,9 @@
27
27
  options={VARIABLE_OPTIONS}
28
28
  value={VARIABLE_OPTIONS.find((opt) => opt.value === component.properties.id)}
29
29
  onUpdate={(value) => {
30
- updateProperty('id', value.value as string, component, onPropertyChange, value.name?.split('—')[1].trim())
30
+ updateProperty('id', value.value as string, component, onPropertyChange)
31
31
  updateProperty('eventHandler.Variables', value.value as string, component, onPropertyChange)
32
+ onPropertyChange(null, value.name?.split('—')[1].trim(), null)
32
33
  }}
33
34
  />
34
35
  </div>
@@ -101,11 +101,11 @@
101
101
  }}
102
102
  />
103
103
  <UI.Select
104
- label={{ name: $t('constructor.props.icon.access') }}
104
+ label={{ name: $t('constructor.props.access') }}
105
105
  type="buttons"
106
106
  options={$optionsStore.ACCESS_OPTION}
107
- value={$optionsStore.ACCESS_OPTION.find((o) => o.value === component.properties.access)}
108
- onUpdate={(option) => updateProperty('acces', option.value as string)}
107
+ value={$optionsStore.ACCESS_OPTION.find((o) => o.value === component.access)}
108
+ onUpdate={(option) => onPropertyChange(null, null, option.value)}
109
109
  />
110
110
  <UI.Select
111
111
  label={{ name: $t('constructor.props.type') }}
@@ -247,6 +247,13 @@
247
247
  />
248
248
  </div>
249
249
  <div class="flex w-1/3 flex-col px-2">
250
+ <UI.Select
251
+ label={{ name: $t('constructor.props.access') }}
252
+ type="buttons"
253
+ options={$optionsStore.ACCESS_OPTION}
254
+ value={$optionsStore.ACCESS_OPTION.find((o) => o.value === component.access)}
255
+ onUpdate={(option) => onPropertyChange(null, null, option.value)}
256
+ />
250
257
  <UI.Input
251
258
  label={{ name: $t('constructor.props.value') }}
252
259
  value={component.properties.value}
@@ -305,7 +305,7 @@
305
305
  </div>
306
306
  </div>
307
307
 
308
- <div class="absolute right-10 flex items-center">
308
+ <div class="right-10 flex items-center md:absolute">
309
309
  <div id={`${id}-${crypto.randomUUID().slice(0, 6)}`} class="flex h-full flex-col justify-center rounded-full p-10">
310
310
  {#each sensitivityOptions as option, index}
311
311
  <button
@@ -105,6 +105,13 @@
105
105
  />
106
106
  </div>
107
107
  <div class="flex w-1/3 flex-col items-center px-2">
108
+ <UI.Select
109
+ label={{ name: $t('constructor.props.access') }}
110
+ type="buttons"
111
+ options={$optionsStore.ACCESS_OPTION}
112
+ value={$optionsStore.ACCESS_OPTION.find((o) => o.value === component.access)}
113
+ onUpdate={(option) => onPropertyChange(null, null, option.value)}
114
+ />
108
115
  <UI.Select
109
116
  label={{ name: $t('constructor.props.type') }}
110
117
  type="buttons"
@@ -131,30 +138,17 @@
131
138
  }}
132
139
  />
133
140
  {#if component.properties.bitMode}
134
- <div class="flex w-full gap-4">
135
- <UI.Input
136
- label={{ name: $t('constructor.props.range.start') }}
137
- value={component.properties.range.start}
138
- onUpdate={(value) => {
139
- updateProperty('range.start', value as number, component, onPropertyChange)
140
- generateBitOptions(component.properties.range.start, component.properties.range.end)
141
- }}
142
- number={{ minNum: 0, maxNum: 31, step: 1 }}
143
- help={{ info: $t('constructor.props.range.start.help') }}
144
- type="number"
145
- />
146
- <UI.Input
147
- label={{ name: $t('constructor.props.range.end') }}
148
- value={component.properties.range.end}
149
- onUpdate={(value) => {
150
- updateProperty('range.end', value as number, component, onPropertyChange)
151
- generateBitOptions(component.properties.range.start, component.properties.range.end)
152
- }}
153
- number={{ minNum: 0, maxNum: 31, step: 1 }}
154
- help={{ info: $t('constructor.props.range.end.help') }}
155
- type="number"
156
- />
157
- </div>
141
+ <UI.Slider
142
+ label={{ name: $t('constructor.props.range') }}
143
+ type="range"
144
+ number={{ minNum: 0, maxNum: 31, step: 1 }}
145
+ value={[component.properties.range.start, component.properties.range.end]}
146
+ onUpdate={(value) => {
147
+ updateProperty('range.start', value[0] as [number, number], component, onPropertyChange)
148
+ updateProperty('range.end', value as number[][1] as number, component, onPropertyChange)
149
+ generateBitOptions(component.properties.range.start, component.properties.range.end)
150
+ }}
151
+ />
158
152
  {/if}
159
153
  </div>
160
154
  <div class="flex w-1/3 flex-col items-center px-2">
@@ -271,6 +265,13 @@
271
265
  value={component.properties.id}
272
266
  onUpdate={(value) => updateProperty('id', value as string, component, onPropertyChange)}
273
267
  />
268
+ <UI.Select
269
+ label={{ name: $t('constructor.props.access') }}
270
+ type="buttons"
271
+ options={$optionsStore.ACCESS_OPTION}
272
+ value={$optionsStore.ACCESS_OPTION.find((o) => o.value === component.access)}
273
+ onUpdate={(option) => onPropertyChange(null, null, option.value)}
274
+ />
274
275
  <UI.Input
275
276
  label={{ name: $t('constructor.props.wrapperclass') }}
276
277
  value={component.properties.wrapperClass}
@@ -1,10 +1,8 @@
1
1
  <!-- $lib/ElementsUI/Slider.svelte -->
2
2
  <script lang="ts">
3
3
  import type { ISliderProps } from '../types'
4
- import IconGripVerticalLeft from '../libIcons/IconGripVerticalLeft.svelte'
5
- import IconGripVerticalRight from '../libIcons/IconGripVerticalRight.svelte'
6
- import IconGripVerticalDual from '../libIcons/IconGripVerticalDual.svelte'
7
4
  import { twMerge } from 'tailwind-merge'
5
+ import { onDestroy, onMount } from 'svelte'
8
6
 
9
7
  let {
10
8
  id = crypto.randomUUID(),
@@ -27,11 +25,6 @@
27
25
  let lowerValue = $derived(isRange && Array.isArray(value) ? value[0] : number.minNum)
28
26
  let upperValue = $derived(isRange && Array.isArray(value) ? value[1] : number.maxNum)
29
27
 
30
- /* Расчет позиций */
31
- const singlePosition = $derived(((singleValue - number.minNum) / (number.maxNum - number.minNum)) * 100)
32
- const lowerPosition = $derived(((lowerValue - number.minNum) / (number.maxNum - number.minNum)) * 100)
33
- const upperPosition = $derived(((upperValue - number.minNum) / (number.maxNum - number.minNum)) * 100)
34
-
35
28
  $effect(() => {
36
29
  if (value === undefined || value === null) {
37
30
  if (type === 'single' && !value) value = number.minNum
@@ -44,8 +37,10 @@
44
37
  if (isRange && target !== 'single') {
45
38
  if (target === 'lower') {
46
39
  lowerValue = Math.max(number.minNum, Math.min(lowerValue + stepValue, upperValue))
40
+ lowerValue = lowerValue == upperValue ? upperValue - number.step : lowerValue
47
41
  } else {
48
42
  upperValue = Math.min(number.maxNum, Math.max(upperValue + stepValue, lowerValue))
43
+ upperValue = upperValue == lowerValue ? upperValue + number.step : upperValue
49
44
  }
50
45
  onUpdate([lowerValue, upperValue])
51
46
  } else {
@@ -80,19 +75,65 @@
80
75
 
81
76
  if (activeThumb === 'lower') {
82
77
  lowerValue = Math.max(number.minNum, Math.min(clickValue, upperValue))
78
+ lowerValue = lowerValue == upperValue ? upperValue - number.step : lowerValue
83
79
  } else {
84
80
  upperValue = Math.min(number.maxNum, Math.max(clickValue, lowerValue))
81
+ upperValue = upperValue == lowerValue ? upperValue + number.step : upperValue
85
82
  }
86
-
87
83
  onUpdate([lowerValue, upperValue])
88
84
  } else {
89
85
  singleValue = Math.max(number.minNum, Math.min(clickValue, number.maxNum))
90
86
  onUpdate(singleValue)
91
87
  }
92
88
  }
89
+
90
+ let rangeRefLower: HTMLElement | null = $state(null)
91
+ let rangeRefUpper: HTMLElement | null = $state(null)
92
+ let shadowWidth = $state()
93
+
94
+ const updateShadowWidth = () => {
95
+ let thumbCenterLower
96
+ let thumbCenterUpper
97
+
98
+ if (rangeRefLower) {
99
+ const rect = rangeRefLower.getBoundingClientRect()
100
+ const percent = (lowerValue - number.minNum) / (number.maxNum - number.minNum)
101
+ thumbCenterLower = rect.left + rect.width * percent
102
+ }
103
+
104
+ if (rangeRefUpper) {
105
+ const rect = rangeRefUpper.getBoundingClientRect()
106
+ const percent = (upperValue - number.minNum) / (number.maxNum - number.minNum)
107
+ thumbCenterUpper = rect.left + rect.width * percent
108
+ }
109
+
110
+ if (thumbCenterUpper && thumbCenterLower) {
111
+ shadowWidth = (thumbCenterUpper - thumbCenterLower) / 3.5
112
+ }
113
+ }
114
+
115
+ $effect(() => {
116
+ lowerValue
117
+ upperValue
118
+ updateShadowWidth()
119
+ })
120
+
121
+ onMount(() => {
122
+ if (window.visualViewport) {
123
+ const handleResize = () => {
124
+ updateShadowWidth()
125
+ }
126
+
127
+ window.visualViewport.addEventListener('resize', handleResize)
128
+
129
+ onDestroy(() => {
130
+ if (window.visualViewport) window.visualViewport.removeEventListener('resize', handleResize)
131
+ })
132
+ }
133
+ })
93
134
  </script>
94
135
 
95
- <div class={twMerge(`relative flex w-full flex-col items-center `, wrapperClass)}>
136
+ <div class={twMerge(`bg-blue relative flex w-full flex-col items-center `, wrapperClass)}>
96
137
  {#if label.name}
97
138
  <h5 class={twMerge(`w-full px-4 text-center`, label.class)}>{label.name}</h5>
98
139
  {/if}
@@ -100,22 +141,24 @@
100
141
  <!-- Слайдер -->
101
142
  <div
102
143
  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' : ''}"
144
+ class="relative flex h-9 w-full justify-center rounded-full {disabled ? 'cursor-not-allowed opacity-50' : ''}"
104
145
  >
105
146
  {#if isRange}
147
+ {@const userAgent = navigator.userAgent}
106
148
  <!-- Трек и активная зона -->
107
149
  <div
108
- class={`absolute h-full w-full rounded-full bg-(--gray-color) ${disabled ? '' : 'cursor-pointer'}`}
150
+ class={`absolute z-10 h-full w-full rounded-full bg-transparent ${disabled ? '' : 'cursor-pointer'}`}
109
151
  role="button"
110
152
  tabindex={null}
111
153
  onkeydown={null}
112
- onclick={disabled ? undefined : handleTrackClick}
113
- >
114
- <div class="absolute h-full rounded-full bg-(--bg-color)" style={`left: ${lowerPosition}%; right: ${100 - upperPosition}%;`}></div>
115
- </div>
154
+ onclick={(e) => {
155
+ disabled ? undefined : handleTrackClick(e)
156
+ }}
157
+ ></div>
116
158
 
117
159
  <!-- Ползунки -->
118
160
  <input
161
+ bind:this={rangeRefLower}
119
162
  type="range"
120
163
  min={number.minNum}
121
164
  max={number.maxNum}
@@ -126,20 +169,47 @@
126
169
  : (e) => {
127
170
  const newValue = Math.min(Number((e.target as HTMLInputElement).value), upperValue)
128
171
  lowerValue = newValue
129
- activeThumb = 'lower'
172
+ lowerValue = newValue == upperValue ? upperValue - number.step : newValue
130
173
  }}
131
- onmouseup={disabled ? undefined : () => onUpdate([lowerValue, upperValue])}
174
+ onmouseup={(e) => {
175
+ handleTrackClick(e)
176
+ disabled ? undefined : () => onUpdate([lowerValue, upperValue])
177
+ }}
132
178
  {disabled}
133
- class={`absolute h-full w-full appearance-none bg-transparent ${activeThumb === 'lower' ? 'z-30' : 'z-20'}`}
179
+ class={twMerge(
180
+ `slider-bg absolute h-8 w-full appearance-none overflow-hidden rounded-full accent-(--back-color)
181
+ [&::-webkit-slider-runnable-track]:rounded-full
182
+ [&::-webkit-slider-runnable-track]:bg-(--gray-color)
183
+ [&::-webkit-slider-thumb]:relative
184
+ [&::-webkit-slider-thumb]:z-100
185
+ [&::-webkit-slider-thumb]:ml-[-0.4rem]
186
+ [&::-webkit-slider-thumb]:h-4
187
+ [&::-webkit-slider-thumb]:w-4
188
+ [&::-webkit-slider-thumb]:cursor-pointer
189
+ [&::-webkit-slider-thumb]:rounded-full
190
+ [&::-webkit-slider-thumb]:shadow-[var(--focus-shadow),]
191
+ ${
192
+ userAgent.includes('iOS') || userAgent.includes('iPhone') || userAgent.includes('iPad')
193
+ ? 'pl-3.5 [&::-webkit-slider-thumb]:ring-[6.5px]'
194
+ : 'pl-3 [&::-webkit-slider-thumb]:ring-[5px]'
195
+ }
196
+ [&::-moz-range-thumb]:relative
197
+ [&::-moz-range-thumb]:ml-[-0.4rem]
198
+ [&::-moz-range-thumb]:size-4
199
+ [&::-moz-range-thumb]:cursor-pointer
200
+ [&::-moz-range-thumb]:rounded-full
201
+ [&::-moz-range-thumb]:shadow-[var(--focus-shadow),]
202
+ [&::-moz-range-thumb]:ring-[6px]
203
+ [&::-moz-range-track]:rounded-full
204
+ [&::-moz-range-track]:bg-(--gray-color)
205
+ `,
206
+ `[&::-moz-range-thumb]:shadow-[calc(100rem*-1-0.5rem)_0_0_100rem]
207
+ [&::-webkit-slider-thumb]:shadow-[calc(${shadowWidth}px+0.5rem)_0_0_${shadowWidth}px]`,
208
+ )}
134
209
  />
135
- <div
136
- class="pointer-events-none absolute z-40 rounded-full bg-(--field-color)"
137
- style={`left: calc(${lowerPosition}% + 0rem); top: 50%; transform: translateY(-50%)`}
138
- >
139
- <IconGripVerticalLeft />
140
- </div>
141
210
 
142
211
  <input
212
+ bind:this={rangeRefUpper}
143
213
  type="range"
144
214
  min={number.minNum}
145
215
  max={number.maxNum}
@@ -150,59 +220,90 @@
150
220
  : (e) => {
151
221
  const newValue = Math.max(Number((e.target as HTMLInputElement).value), lowerValue)
152
222
  upperValue = newValue
153
- activeThumb = 'upper'
223
+ upperValue = newValue == lowerValue ? newValue + number.step : upperValue
154
224
  }}
155
- onmouseup={disabled ? undefined : () => onUpdate([lowerValue, upperValue])}
225
+ onmouseup={(e) => {
226
+ handleTrackClick(e)
227
+ disabled ? undefined : () => onUpdate([lowerValue, upperValue])
228
+ }}
156
229
  {disabled}
157
- class={`absolute h-full w-full appearance-none bg-transparent ${activeThumb === 'upper' ? 'z-30' : 'z-20'}`}
230
+ class={twMerge(
231
+ `slider-bg absolute h-8 w-full appearance-none overflow-hidden rounded-full accent-(--back-color)
232
+ [&::-webkit-slider-runnable-track]:rounded-full
233
+ [&::-webkit-slider-thumb]:relative
234
+ [&::-webkit-slider-thumb]:z-100
235
+ [&::-webkit-slider-thumb]:ml-[-0.4rem]
236
+ [&::-webkit-slider-thumb]:h-4
237
+ [&::-webkit-slider-thumb]:w-4
238
+ [&::-webkit-slider-thumb]:cursor-pointer
239
+ [&::-webkit-slider-thumb]:rounded-full
240
+ [&::-webkit-slider-thumb]:shadow-[var(--focus-shadow),]
241
+ ${
242
+ userAgent.includes('iOS') || userAgent.includes('iPhone') || userAgent.includes('iPad')
243
+ ? 'pl-3.5 [&::-webkit-slider-thumb]:ring-[6.5px]'
244
+ : 'pl-3 [&::-webkit-slider-thumb]:ring-[5px]'
245
+ }
246
+ [&::-moz-range-thumb]:relative
247
+ [&::-moz-range-thumb]:ml-[-0.4rem]
248
+ [&::-moz-range-thumb]:size-4
249
+ [&::-moz-range-thumb]:cursor-pointer
250
+ [&::-moz-range-thumb]:rounded-full
251
+ [&::-moz-range-thumb]:shadow-[var(--focus-shadow),]
252
+ [&::-moz-range-thumb]:ring-[6px]
253
+ [&::-moz-range-track]:rounded-full
254
+ [&::-moz-range-track]:bg-(--gray-color)
255
+ `,
256
+ `[&::-moz-range-thumb]:shadow-[calc(100rem*-1-0.5rem)_0_0_100rem]
257
+ ${shadowWidth ? '' : ''} [&::-webkit-slider-thumb]:shadow-[calc(${shadowWidth}px*-1-0.5rem)_0_0_${shadowWidth}px]`,
258
+ )}
158
259
  />
159
- <div
160
- class="pointer-events-none absolute z-40 rounded-full bg-(--field-color)"
161
- style={`left: calc(${upperPosition}% - 2rem); top: 50%; transform: translateY(-50%)`}
162
- >
163
- <IconGripVerticalRight />
164
- </div>
165
260
  {:else}
261
+ {@const userAgent = navigator.userAgent}
166
262
  <!-- Одиночный слайдер -->
167
- <div
168
- class={`absolute h-full w-full rounded-full bg-(--gray-color) ${disabled ? '' : 'cursor-pointer'}`}
169
- role="button"
170
- tabindex={null}
171
- onkeydown={null}
172
- onclick={disabled ? undefined : handleTrackClick}
173
- >
174
- <div
175
- class="absolute z-10 h-full {singlePosition === 100 ? ' rounded-full' : 'rounded-l-full'}"
176
- style={`width: ${singlePosition}%; background-color: var(--bg-color)`}
177
- ></div>
178
- </div>
263
+ <div class="absolute h-full w-full">
264
+ <input
265
+ type="range"
266
+ class={twMerge(
267
+ `slider-bg h-8 w-full appearance-none overflow-hidden rounded-full accent-(--back-color)
268
+ [&::-webkit-slider-runnable-track]:rounded-full
269
+ [&::-webkit-slider-runnable-track]:bg-(--gray-color)
270
+ [&::-webkit-slider-thumb]:relative
179
271
 
180
- <input
181
- type="range"
182
- min={number.minNum}
183
- max={number.maxNum}
184
- step={number.step}
185
- bind:value={singleValue}
186
- oninput={disabled
187
- ? undefined
188
- : (e) => {
189
- singleValue = Number((e.target as HTMLInputElement).value)
190
- }}
191
- onmouseup={disabled ? undefined : () => onUpdate(singleValue)}
192
- {disabled}
193
- class="absolute z-20 h-full w-full appearance-none"
194
- />
195
- <div
196
- class="pointer-events-none absolute z-30 rounded-full bg-(--field-color)"
197
- style={`left: clamp(1rem, ${singlePosition}%, calc(100% - 1rem)); top: 50%; transform: translate(-50%, -50%)`}
198
- >
199
- <IconGripVerticalDual />
272
+ [&::-webkit-slider-thumb]:ml-[-0.4rem]
273
+ [&::-webkit-slider-thumb]:h-4
274
+ [&::-webkit-slider-thumb]:w-4
275
+ [&::-webkit-slider-thumb]:cursor-pointer
276
+ [&::-webkit-slider-thumb]:rounded-full
277
+ [&::-webkit-slider-thumb]:shadow-[var(--focus-shadow),]
278
+ ${
279
+ userAgent.includes('iOS') || userAgent.includes('iPhone') || userAgent.includes('iPad')
280
+ ? 'pl-3.5 [&::-webkit-slider-thumb]:ring-[6.5px]'
281
+ : 'pl-3 [&::-webkit-slider-thumb]:ring-[5px]'
282
+ }
283
+ [&::-moz-range-thumb]:relative
284
+ [&::-moz-range-thumb]:ml-[-0.4rem]
285
+ [&::-moz-range-thumb]:size-4
286
+ [&::-moz-range-thumb]:cursor-pointer
287
+ [&::-moz-range-thumb]:rounded-full
288
+ [&::-moz-range-thumb]:shadow-[var(--focus-shadow),]
289
+ [&::-moz-range-thumb]:ring-[6px]
290
+ [&::-moz-range-track]:rounded-full
291
+ [&::-moz-range-track]:bg-(--gray-color)
292
+ `,
293
+ `[&::-moz-range-thumb]:shadow-[calc(100rem*-1-0.5rem)_0_0_100rem]
294
+ [&::-webkit-slider-thumb]:shadow-[calc(100rem*-1-0.5rem)_0_0_100rem]`,
295
+ )}
296
+ min={number.minNum}
297
+ max={number.maxNum}
298
+ step={number.step}
299
+ bind:value={singleValue}
300
+ />
200
301
  </div>
201
302
  {/if}
202
303
  </div>
203
304
 
204
305
  <!-- Кнопки управления -->
205
- <div class={`mt-2 flex w-full ${isRange ? 'justify-between' : 'justify-center'} gap-2`}>
306
+ <div class={`mt-3 flex w-full ${isRange ? 'justify-between' : 'justify-center'} gap-2`}>
206
307
  {#if isRange}
207
308
  {#each ['lower', 'upper'] as type (type)}
208
309
  <div
@@ -246,64 +347,3 @@
246
347
  {/if}
247
348
  </div>
248
349
  </div>
249
-
250
- <style>
251
- input[type='range'] {
252
- -webkit-appearance: none;
253
- appearance: none;
254
- margin: 0;
255
- padding: 0;
256
- pointer-events: none;
257
- outline: none;
258
- }
259
-
260
- /* Webkit thumb */
261
- input[type='range']::-webkit-slider-thumb {
262
- -webkit-appearance: none;
263
- appearance: none;
264
- width: 2rem;
265
- height: 2rem;
266
- border-radius: 50%;
267
- background: transparent;
268
- cursor: pointer;
269
- pointer-events: auto;
270
- border: none;
271
- }
272
-
273
- /* Firefox thumb */
274
- input[type='range']::-moz-range-thumb {
275
- width: 2rem;
276
- height: 2rem;
277
- border-radius: 50%;
278
- background: transparent;
279
- cursor: pointer;
280
- pointer-events: auto;
281
- border: none;
282
- }
283
-
284
- /* Webkit track */
285
- input[type='range']::-webkit-slider-runnable-track {
286
- width: 100%;
287
- height: 100%;
288
- background: transparent;
289
- border-radius: 0;
290
- border: none;
291
- }
292
-
293
- /* Firefox track */
294
- input[type='range']::-moz-range-track {
295
- width: 100%;
296
- height: 100%;
297
- background: transparent;
298
- border-radius: 0;
299
- border: none;
300
- }
301
-
302
- input[type='range']:disabled::-webkit-slider-thumb {
303
- cursor: not-allowed;
304
- }
305
-
306
- input[type='range']:disabled::-moz-range-thumb {
307
- cursor: not-allowed;
308
- }
309
- </style>
@@ -40,8 +40,9 @@
40
40
  options={VARIABLE_OPTIONS}
41
41
  value={VARIABLE_OPTIONS.find((opt) => opt.value === component.properties.id)}
42
42
  onUpdate={(value) => {
43
- updateProperty('id', value.value as string, component, onPropertyChange, value.name?.split('—')[1].trim())
43
+ updateProperty('id', value.value as string, component, onPropertyChange)
44
44
  updateProperty('eventHandler.Variables', value.value as string, component, onPropertyChange)
45
+ onPropertyChange(null, value.name?.split('—')[1].trim(), null)
45
46
  }}
46
47
  />
47
48
  <UI.Select
@@ -53,6 +54,13 @@
53
54
  updateProperty('eventHandler.Argument', option.value as string, component, onPropertyChange)
54
55
  }}
55
56
  />
57
+ <UI.Select
58
+ label={{ name: $t('constructor.props.access') }}
59
+ type="buttons"
60
+ options={$optionsStore.ACCESS_OPTION}
61
+ value={$optionsStore.ACCESS_OPTION.find((o) => o.value === component.access)}
62
+ onUpdate={(option) => onPropertyChange(null, null, option.value)}
63
+ />
56
64
  </div>
57
65
  <div class="flex w-1/3 flex-col px-2">
58
66
  <UI.Select
@@ -144,6 +152,13 @@
144
152
  />
145
153
  </div>
146
154
  <div class="flex w-1/3 flex-col px-2">
155
+ <UI.Select
156
+ label={{ name: $t('constructor.props.access') }}
157
+ type="buttons"
158
+ options={$optionsStore.ACCESS_OPTION}
159
+ value={$optionsStore.ACCESS_OPTION.find((o) => o.value === component.access)}
160
+ onUpdate={(option) => onPropertyChange(null, null, option.value)}
161
+ />
147
162
  <UI.Input
148
163
  label={{ name: $t('constructor.props.label') }}
149
164
  value={component.properties.label.name}
@@ -36,8 +36,9 @@
36
36
  options={VARIABLE_OPTIONS}
37
37
  value={VARIABLE_OPTIONS.find((opt) => opt.value === component.properties.id)}
38
38
  onUpdate={(value) => {
39
- updateProperty('id', value.value as string, component, onPropertyChange, value.name?.split('—')[1].trim())
39
+ updateProperty('id', value.value as string, component, onPropertyChange)
40
40
  updateProperty('eventHandler.Variables', value.value as string, component, onPropertyChange)
41
+ onPropertyChange(null, value.name?.split('—')[1].trim(), null)
41
42
  }}
42
43
  />
43
44
  <UI.Select
@@ -49,6 +50,16 @@
49
50
  updateProperty('eventHandler.Argument', option.value as string, component, onPropertyChange)
50
51
  }}
51
52
  />
53
+ <UI.Select
54
+ label={{ name: $t('constructor.props.access') }}
55
+ type="buttons"
56
+ options={$optionsStore.ACCESS_OPTION}
57
+ value={$optionsStore.ACCESS_OPTION.find((o) => o.value === component.access)}
58
+ onUpdate={(option) => onPropertyChange(null, null, option.value)}
59
+ />
60
+ </div>
61
+
62
+ <div class="flex w-1/3 flex-col px-2">
52
63
  <UI.Select
53
64
  wrapperClass="!h-14"
54
65
  label={{ name: $t('constructor.props.type') }}
@@ -58,9 +69,7 @@
58
69
  value={$optionsStore.SWITCH_OPTIONS.find((option) => option.value == component.properties.type)}
59
70
  onUpdate={(option) => updateProperty('type', option.value as string, component, onPropertyChange)}
60
71
  />
61
- </div>
62
- {#if !component.properties.bitMode}
63
- <div class="flex w-1/3 flex-col px-2">
72
+ {#if !component.properties.bitMode}
64
73
  <UI.Input
65
74
  label={{ name: $t('constructor.props.caption.left') }}
66
75
  value={component.properties.label.captionLeft}
@@ -83,8 +92,9 @@
83
92
  updateProperty('options', options, component, onPropertyChange)
84
93
  }}
85
94
  />
86
- </div>
87
- {/if}
95
+ {/if}
96
+ </div>
97
+
88
98
  <div class="flex w-1/3 flex-col px-2">
89
99
  <UI.Input
90
100
  label={{ name: $t('constructor.props.label') }}
@@ -215,6 +225,13 @@
215
225
  value={component.properties.id}
216
226
  onUpdate={(value) => updateProperty('id', value as string, component, onPropertyChange)}
217
227
  />
228
+ <UI.Select
229
+ label={{ name: $t('constructor.props.access') }}
230
+ type="buttons"
231
+ options={$optionsStore.ACCESS_OPTION}
232
+ value={$optionsStore.ACCESS_OPTION.find((o) => o.value === component.access)}
233
+ onUpdate={(option) => onPropertyChange(null, null, option.value)}
234
+ />
218
235
  <UI.Input
219
236
  label={{ name: $t('constructor.props.wrapperclass') }}
220
237
  value={component.properties.wrapperClass}
@@ -166,13 +166,13 @@
166
166
  {#each header as column, index (column)}
167
167
  <div
168
168
  class={twMerge(
169
- `justify-center border-l ${outline && index !== 0 ? ' border-(--border-color)' : 'border-transparent'} ${
169
+ `items-center justify-center border-l ${outline && index !== 0 ? ' border-(--border-color)' : 'border-transparent'} ${
170
170
  column.align?.header === 'center'
171
171
  ? 'flex justify-center text-center'
172
172
  : column.align?.header === 'right'
173
173
  ? 'flex justify-end text-right'
174
174
  : 'flex justify-start text-left'
175
- } bg-(--bg-color) p-2 text-left`,
175
+ } gap-1 bg-(--bg-color) p-2 text-left`,
176
176
  column.label?.class,
177
177
  )}
178
178
  >
@@ -81,10 +81,18 @@
81
81
  options={VARIABLE_OPTIONS}
82
82
  value={VARIABLE_OPTIONS.find((opt) => opt.value === component.properties.id)}
83
83
  onUpdate={(value) => {
84
- updateProperty('id', value.value as string, component, onPropertyChange, value.name?.split('—')[1].trim())
84
+ updateProperty('id', value.value as string, component, onPropertyChange)
85
85
  updateProperty('eventHandler.Variables', value.value as string, component, onPropertyChange)
86
+ onPropertyChange(null, value.name?.split('—')[1].trim(), null)
86
87
  }}
87
88
  />
89
+ <UI.Select
90
+ label={{ name: $t('constructor.props.access') }}
91
+ type="buttons"
92
+ options={$optionsStore.ACCESS_OPTION}
93
+ value={$optionsStore.ACCESS_OPTION.find((o) => o.value === component.access)}
94
+ onUpdate={(option) => onPropertyChange(null, null, option.value)}
95
+ />
88
96
  </div>
89
97
  <div class="flex w-1/3 flex-col px-2">
90
98
  <UI.Select
@@ -145,6 +153,7 @@
145
153
  <div class="mr-2 flex items-end justify-around gap-6">
146
154
  <UI.Input
147
155
  label={{ name: $t('constructor.props.table.columns.key') }}
156
+ wrapperClass="w-170"
148
157
  value={column.key}
149
158
  help={{ regExp: /^[0-9a-zA-Z_-]{0,16}$/ }}
150
159
  onUpdate={(value) => {
@@ -161,21 +170,30 @@
161
170
  />
162
171
  <UI.Input
163
172
  label={{ name: $t('constructor.props.table.columns.width') }}
164
- wrapperClass="w-120"
173
+ wrapperClass="w-150"
165
174
  type="number"
166
175
  value={Number(column.width.replace('%', ''))}
167
176
  onUpdate={(value) => updateTableHeader(columnIndex, 'width', `${value}%`)}
168
177
  />
178
+ <UI.Select
179
+ label={{ name: $t('constructor.props.align.content') }}
180
+ type="buttons"
181
+ value={$optionsStore.ALIGN_OPTIONS.find((a) => (a.value as string).includes(column.align?.content) || 'left')}
182
+ options={$optionsStore.ALIGN_OPTIONS}
183
+ onUpdate={(option) => {
184
+ updateTableHeader(columnIndex, 'align', { header: option.value, content: option.value })
185
+ }}
186
+ />
169
187
  <UI.Switch
170
- wrapperClass="w-2/10"
171
- label={{ name: $t('constructor.props.table.columns.sortable') }}
188
+ wrapperClass="w-30"
189
+ label={{ name: $t('constructor.props.table.columns.sortable'), class: 'px-0' }}
172
190
  options={[{ id: crypto.randomUUID(), value: 0, class: '' }]}
173
191
  value={column.sortable}
174
192
  onChange={(value) => updateTableHeader(columnIndex, 'sortable', value)}
175
193
  />
176
194
  <UI.Switch
177
- wrapperClass="w-2/10"
178
- label={{ name: $t('constructor.props.copy') }}
195
+ wrapperClass="w-30"
196
+ label={{ name: $t('constructor.props.copy'), class: 'px-0' }}
179
197
  options={[{ id: crypto.randomUUID(), value: 0, class: '' }]}
180
198
  value={column.overflow?.copy}
181
199
  onChange={(value) => updateTableHeader(columnIndex, 'overflow', { copy: value })}
@@ -263,6 +281,7 @@
263
281
  value={component.properties.id}
264
282
  onUpdate={(value) => updateProperty('id', value as string, component, onPropertyChange)}
265
283
  />
284
+
266
285
  <UI.Input
267
286
  label={{ name: $t('constructor.props.wrapperclass') }}
268
287
  value={component.properties.wrapperClass}
@@ -285,6 +304,13 @@
285
304
  />
286
305
  </div>
287
306
  <div class="flex w-1/3 flex-col px-2">
307
+ <UI.Select
308
+ label={{ name: $t('constructor.props.access') }}
309
+ type="buttons"
310
+ options={$optionsStore.ACCESS_OPTION}
311
+ value={$optionsStore.ACCESS_OPTION.find((o) => o.value === component.access)}
312
+ onUpdate={(option) => onPropertyChange(null, null, option.value)}
313
+ />
288
314
  <UI.Input
289
315
  label={{ name: $t('constructor.props.label') }}
290
316
  value={component.properties.label.name}
@@ -30,8 +30,8 @@
30
30
  (c.value as string).includes(component.properties.wrapperClass?.split(' ').find((cls: string) => cls.startsWith('text-'))),
31
31
  ),
32
32
  )
33
- const initialBold = $derived(component.properties.content?.class?.split(' ').find((cls: string) => cls.startsWith('font-bold')))
34
- const initialItalic = $derived(component.properties.content?.class?.split(' ').find((cls: string) => cls.startsWith('italic')))
33
+ const initialBold = $derived(component.properties.content?.class?.split(' ').some((cls: string) => cls.includes('font-bold')))
34
+ const initialItalic = $derived(component.properties.content?.class?.split(' ').some((cls: string) => cls.startsWith('italic')))
35
35
  </script>
36
36
 
37
37
  {#if forConstructor}
@@ -42,8 +42,9 @@
42
42
  options={VARIABLE_OPTIONS}
43
43
  value={VARIABLE_OPTIONS.find((opt) => opt.value === component.properties.id)}
44
44
  onUpdate={(value) => {
45
- updateProperty('id', value.value as string, component, onPropertyChange, value.name?.split('—')[1].trim())
45
+ updateProperty('id', value.value as string, component, onPropertyChange)
46
46
  updateProperty('eventHandler.Variables', value.value as string, component, onPropertyChange)
47
+ onPropertyChange(null, value.name?.split('—')[1].trim(), null)
47
48
  }}
48
49
  />
49
50
  <UI.Input
@@ -77,6 +78,7 @@
77
78
  />
78
79
  </div>
79
80
  <div class="flex w-1/3 flex-col px-2">
81
+ <!-- <p>{component.properties.content?.class?.split(' ').includes((cls: string) => cls.startsWith('font-bold'))}</p> -->
80
82
  <UI.Switch
81
83
  label={{ name: $t('constructor.props.bold') }}
82
84
  value={initialBold}
@@ -84,7 +86,7 @@
84
86
  onChange={(value) =>
85
87
  updateProperty(
86
88
  'content.class',
87
- `${component.properties.content.class} ${value ? 'font-bold' : 'font-normal'}`,
89
+ twMerge(`${component.properties.content.class} ${value ? 'font-bold' : 'font-normal'}`),
88
90
  component,
89
91
  onPropertyChange,
90
92
  )}
@@ -94,7 +96,12 @@
94
96
  value={initialItalic}
95
97
  options={[{ id: crypto.randomUUID(), value: 0, class: '' }]}
96
98
  onChange={(value) =>
97
- updateProperty('content.class', `${component.properties.content.class} ${value ? 'italic' : 'not-italic'}`, component, onPropertyChange)}
99
+ updateProperty(
100
+ 'content.class',
101
+ twMerge(`${component.properties.content.class} ${value ? 'italic' : 'not-italic'}`),
102
+ component,
103
+ onPropertyChange,
104
+ )}
98
105
  />
99
106
  <UI.Switch
100
107
  label={{ name: $t('constructor.props.background') }}
@@ -41,7 +41,7 @@ const translations = {
41
41
  'constructor.props.type.vertical': 'Вертикально',
42
42
  'constructor.props.type.checkbox': 'Галочка',
43
43
  'constructor.props.type.full': 'Полный',
44
- 'constructor.props.type.viewOnly': 'Только просмотр',
44
+ 'constructor.props.type.viewOnly': 'Просмотр',
45
45
  'constructor.props.type.hidden': 'Скрыто',
46
46
  /* Общие для редактора свойств */
47
47
  'constructor.props.id': 'Идентификатор',
@@ -67,7 +67,7 @@ const translations = {
67
67
  'constructor.props.variables.info': 'Поле для ввода имён переменных, разделенных пробелами',
68
68
  'constructor.props.value': 'Значение',
69
69
  'constructor.props.value.info': 'Поле для ввода Value пакета в формате JSON',
70
- 'constructor.props.align': 'Выравнивание',
70
+ 'constructor.props.align': 'Выравнивание надписи',
71
71
  'constructor.props.align.header': 'Выравнивание заголовка',
72
72
  'constructor.props.align.content': 'Выравнивание контента',
73
73
  'constructor.props.image': 'Фоновое изображение',
@@ -120,13 +120,11 @@ const translations = {
120
120
  'constructor.props.copy': 'Копирование',
121
121
  'constructor.props.size.height': 'Высота сетки',
122
122
  'constructor.props.size.width': 'Ширина сетки',
123
- 'constructor.props.range.start': 'Начальный бит ',
124
- 'constructor.props.range.end': 'Последний бит',
125
- 'constructor.props.range.start.help': 'Позиция начального бита диапазона ',
126
- 'constructor.props.range.end.help': 'Позиция последнего бита диапазона',
123
+ 'constructor.props.range': 'Диапазон позиции битов ',
127
124
  'constructor.props.icon.text.position': 'Положение иконки',
128
125
  'constructor.props.equal': 'Равные',
129
126
  'constructor.props.bitmode': 'Битовый режим',
127
+ 'constructor.props.access': 'Доступ (не для владельца)',
130
128
  'constructor.props.table.columns': 'Колонки таблицы',
131
129
  'constructor.props.table.columns.key': 'Ключ',
132
130
  'constructor.props.table.columns.label': 'Название колонки',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "poe-svelte-ui-lib",
3
- "version": "1.2.25",
3
+ "version": "1.2.26",
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.10",
51
+ "svelte": "^5.43.12",
52
52
  "svelte-preprocess": "^6.0.3",
53
53
  "vite": "^7.2.2",
54
54
  "vite-plugin-compression": "^0.5.1"