poe-svelte-ui-lib 1.2.26 → 1.2.28
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.
- package/dist/Button/ButtonProps.svelte +8 -15
- package/dist/FileAttach/FileAttachProps.svelte +2 -0
- package/dist/Input/InputProps.svelte +8 -2
- package/dist/Joystick/Joystick.svelte +0 -1
- package/dist/Map/Map.svelte +205 -0
- package/dist/Map/Map.svelte.d.ts +4 -0
- package/dist/Map/MapProps.svelte +157 -0
- package/dist/Map/MapProps.svelte.d.ts +11 -0
- package/dist/Select/SelectProps.svelte +6 -3
- package/dist/Slider/Slider.svelte +86 -159
- package/dist/index.d.ts +3 -1
- package/dist/index.js +2 -0
- package/dist/locales/translations.js +2 -0
- package/dist/types.d.ts +20 -2
- package/package.json +6 -5
|
@@ -179,13 +179,6 @@
|
|
|
179
179
|
value={$optionsStore.INFO_SIDE_OPTIONS.find((h) => h.value === component.properties.content.info.side)}
|
|
180
180
|
onUpdate={(option) => updateProperty('content.info.side', option.value as string, component, onPropertyChange)}
|
|
181
181
|
/>
|
|
182
|
-
<UI.Input
|
|
183
|
-
label={{ name: $t('constructor.props.svgicon') }}
|
|
184
|
-
type="text-area"
|
|
185
|
-
maxlength={100000}
|
|
186
|
-
value={component.properties.content.icon}
|
|
187
|
-
onUpdate={(value) => updateProperty('content.icon', value as string, component, onPropertyChange)}
|
|
188
|
-
/>
|
|
189
182
|
</div>
|
|
190
183
|
<div class="flex w-1/3 flex-col px-2">
|
|
191
184
|
<UI.Input
|
|
@@ -193,14 +186,6 @@
|
|
|
193
186
|
value={component.properties.componentClass}
|
|
194
187
|
onUpdate={(value) => updateProperty('componentClass', value as string, component, onPropertyChange)}
|
|
195
188
|
/>
|
|
196
|
-
<UI.Select
|
|
197
|
-
label={{ name: $t('constructor.props.height') }}
|
|
198
|
-
type="buttons"
|
|
199
|
-
options={$optionsStore.HEIGHT_OPTIONS}
|
|
200
|
-
value={initialHeight}
|
|
201
|
-
onUpdate={(option) =>
|
|
202
|
-
updateProperty('componentClass', twMerge(component.properties.componentClass, option.value), component, onPropertyChange)}
|
|
203
|
-
/>
|
|
204
189
|
<UI.Select
|
|
205
190
|
wrapperClass="h-14"
|
|
206
191
|
label={{ name: $t('constructor.props.colors') }}
|
|
@@ -210,6 +195,14 @@
|
|
|
210
195
|
onUpdate={(option) =>
|
|
211
196
|
updateProperty('componentClass', twMerge(component.properties.componentClass, option.value), component, onPropertyChange)}
|
|
212
197
|
/>
|
|
198
|
+
|
|
199
|
+
<UI.Input
|
|
200
|
+
label={{ name: $t('constructor.props.svgicon') }}
|
|
201
|
+
type="text-area"
|
|
202
|
+
maxlength={100000}
|
|
203
|
+
value={component.properties.content.icon}
|
|
204
|
+
onUpdate={(value) => updateProperty('content.icon', value as string, component, onPropertyChange)}
|
|
205
|
+
/>
|
|
213
206
|
</div>
|
|
214
207
|
</div>
|
|
215
208
|
{/if}
|
|
@@ -31,6 +31,8 @@
|
|
|
31
31
|
value={component.properties.wrapperClass}
|
|
32
32
|
onUpdate={(value) => updateProperty('wrapperClass', value as string, component, onPropertyChange)}
|
|
33
33
|
/>
|
|
34
|
+
</div>
|
|
35
|
+
<div class="flex w-1/3 flex-col px-2">
|
|
34
36
|
<UI.Input
|
|
35
37
|
label={{ name: $t('constructor.props.label') }}
|
|
36
38
|
value={component.properties.label.name}
|
|
@@ -128,7 +128,10 @@
|
|
|
128
128
|
maxlength={150}
|
|
129
129
|
help={{ info: $t('constructor.props.regexp.info') }}
|
|
130
130
|
componentClass={isValidRegExp === false ? '!border-2 !border-red-400' : ''}
|
|
131
|
-
onUpdate={(value) =>
|
|
131
|
+
onUpdate={(value) => {
|
|
132
|
+
console.log(value)
|
|
133
|
+
updateProperty('help.regExp', value as string)
|
|
134
|
+
}}
|
|
132
135
|
/>
|
|
133
136
|
{:else if component.properties.type === 'number' && !component.properties.readonly && !component.properties.disabled}
|
|
134
137
|
<UI.Input
|
|
@@ -170,7 +173,10 @@
|
|
|
170
173
|
label={{ name: $t('constructor.props.readonly') }}
|
|
171
174
|
value={component.properties.readonly}
|
|
172
175
|
options={[{ id: crypto.randomUUID(), value: 0, class: '' }]}
|
|
173
|
-
onChange={(value) =>
|
|
176
|
+
onChange={(value) => {
|
|
177
|
+
updateProperty('readonly', value)
|
|
178
|
+
console.log(component.properties)
|
|
179
|
+
}}
|
|
174
180
|
/>
|
|
175
181
|
<UI.Switch
|
|
176
182
|
label={{ name: $t('constructor.props.copy') }}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
<!-- $lib/ElementsUI/Map.svelte -->
|
|
2
|
+
<script lang="ts">
|
|
3
|
+
import { t } from '../locales/i18n'
|
|
4
|
+
import type { IDeviceGNSS, IMapProps } from '../types'
|
|
5
|
+
import { onDestroy, onMount } from 'svelte'
|
|
6
|
+
import { MapLibre, NavigationControl, ScaleControl, GeolocateControl, FullScreenControl, Marker, Popup, CustomControl } from 'svelte-maplibre-gl'
|
|
7
|
+
import { fade } from 'svelte/transition'
|
|
8
|
+
import { twMerge } from 'tailwind-merge'
|
|
9
|
+
|
|
10
|
+
let { id = crypto.randomUUID(), label = { name: '', class: '' }, data = $bindable(), markerIcon }: IMapProps = $props()
|
|
11
|
+
|
|
12
|
+
interface MapDevice extends IDeviceGNSS {
|
|
13
|
+
isFresh: boolean
|
|
14
|
+
timeoutId: number | null
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
let devices: MapDevice[] = $state([])
|
|
18
|
+
let isCopied = $state(false)
|
|
19
|
+
let isDarkMode = $state(false)
|
|
20
|
+
let markerTimeout = $state(30_000)
|
|
21
|
+
|
|
22
|
+
const restartFreshTimer = (index: number) => {
|
|
23
|
+
const device = devices[index]
|
|
24
|
+
// Очистить старый таймер, если есть
|
|
25
|
+
if (device.timeoutId !== null) {
|
|
26
|
+
clearTimeout(device.timeoutId)
|
|
27
|
+
}
|
|
28
|
+
// Запустить новый
|
|
29
|
+
const id = setTimeout(() => {
|
|
30
|
+
if (index < devices.length && devices[index].DevSN === device.DevSN) {
|
|
31
|
+
devices[index].isFresh = false
|
|
32
|
+
devices[index].timeoutId = null
|
|
33
|
+
}
|
|
34
|
+
}, markerTimeout) as unknown as number
|
|
35
|
+
devices[index].timeoutId = id
|
|
36
|
+
devices[index].isFresh = true
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Обработка входящих данных
|
|
40
|
+
$effect(() => {
|
|
41
|
+
if (data) {
|
|
42
|
+
const idx = devices.findIndex((d) => d.DevSN === data?.DevSN)
|
|
43
|
+
if (idx !== -1) {
|
|
44
|
+
// Обновление существующего
|
|
45
|
+
devices[idx] = { ...devices[idx], ...data }
|
|
46
|
+
restartFreshTimer(idx)
|
|
47
|
+
} else {
|
|
48
|
+
// Новое устройство
|
|
49
|
+
const newDevice: MapDevice = {
|
|
50
|
+
...data,
|
|
51
|
+
isFresh: true,
|
|
52
|
+
timeoutId: null,
|
|
53
|
+
}
|
|
54
|
+
devices.push(newDevice)
|
|
55
|
+
restartFreshTimer(devices.length - 1)
|
|
56
|
+
}
|
|
57
|
+
data = null
|
|
58
|
+
}
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
const handleThemeChange = (event: CustomEvent) => {
|
|
62
|
+
isDarkMode = !event.detail.currentTheme
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
onMount(() => {
|
|
66
|
+
if (typeof window !== 'undefined') {
|
|
67
|
+
isDarkMode = localStorage.getItem('AppTheme') !== 'light'
|
|
68
|
+
window.addEventListener('ThemeChange', handleThemeChange as EventListener)
|
|
69
|
+
}
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
onDestroy(() => {
|
|
73
|
+
if (typeof window !== 'undefined') window.addEventListener('ThemeChange', handleThemeChange as EventListener)
|
|
74
|
+
|
|
75
|
+
for (const device of devices) {
|
|
76
|
+
if (device.timeoutId !== null) {
|
|
77
|
+
clearTimeout(device.timeoutId)
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
const timeoutOptions: { label: string; value: number }[] = [
|
|
83
|
+
{ label: '30 sec', value: 30_000 },
|
|
84
|
+
{ label: '1 min', value: 60_000 },
|
|
85
|
+
{ label: '3 min', value: 180_000 },
|
|
86
|
+
{ label: '5 min', value: 300_000 },
|
|
87
|
+
{ label: '10 min', value: 600_000 },
|
|
88
|
+
{ label: '30 min', value: 1_800_000 },
|
|
89
|
+
{ label: '1 h', value: 3_600_000 },
|
|
90
|
+
]
|
|
91
|
+
|
|
92
|
+
const changeTimeout = (val: number) => {
|
|
93
|
+
markerTimeout = val
|
|
94
|
+
// перезапускаем таймеры для всех устройств
|
|
95
|
+
devices.forEach((_, idx) => restartFreshTimer(idx))
|
|
96
|
+
}
|
|
97
|
+
</script>
|
|
98
|
+
|
|
99
|
+
<div id={`${id}-${crypto.randomUUID().slice(0, 6)}`} class="h-full min-h-[200px]">
|
|
100
|
+
{#if label.name}
|
|
101
|
+
<h5 class={twMerge(` w-full px-4 text-center`, label.class)}>{label.name}</h5>
|
|
102
|
+
{/if}
|
|
103
|
+
<MapLibre
|
|
104
|
+
class="h-[calc(100%-2rem)] min-h-[200px]"
|
|
105
|
+
style={isDarkMode
|
|
106
|
+
? 'https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json'
|
|
107
|
+
: 'https://basemaps.cartocdn.com/gl/voyager-gl-style/style.json'}
|
|
108
|
+
zoom={1.5}
|
|
109
|
+
center={{ lat: 30, lng: 0 }}
|
|
110
|
+
>
|
|
111
|
+
<NavigationControl />
|
|
112
|
+
<ScaleControl />
|
|
113
|
+
<GeolocateControl />
|
|
114
|
+
<FullScreenControl />
|
|
115
|
+
|
|
116
|
+
<CustomControl position="top-left">
|
|
117
|
+
<div class="flex items-center gap-2 px-2 py-1 text-black">
|
|
118
|
+
<label for="timeout" class="text-sm font-medium">{$t('constructor.props.map.timeout')}</label>
|
|
119
|
+
<select
|
|
120
|
+
id="timeout"
|
|
121
|
+
class="rounded px-2 py-1 text-sm"
|
|
122
|
+
bind:value={markerTimeout}
|
|
123
|
+
onchange={(e) => changeTimeout(parseInt((e.target as HTMLSelectElement).value))}
|
|
124
|
+
>
|
|
125
|
+
{#each timeoutOptions as opt}
|
|
126
|
+
<option value={opt.value}>{opt.label}</option>
|
|
127
|
+
{/each}
|
|
128
|
+
</select>
|
|
129
|
+
</div>
|
|
130
|
+
</CustomControl>
|
|
131
|
+
|
|
132
|
+
{#each devices as device}
|
|
133
|
+
<Marker lnglat={{ lng: device.NavLon, lat: device.NavLat }}>
|
|
134
|
+
{#snippet content()}
|
|
135
|
+
<div class="flex flex-col items-center justify-center leading-none">
|
|
136
|
+
<div
|
|
137
|
+
class="flex size-8 shrink-0 items-center justify-center [&_svg]:h-full [&_svg]:max-h-full [&_svg]:w-full [&_svg]:max-w-full
|
|
138
|
+
{device.isFresh ? 'text-green-500' : 'text-red-500'}"
|
|
139
|
+
style="rotate: {device.NavHeading - 90}deg;"
|
|
140
|
+
>
|
|
141
|
+
{@html markerIcon ||
|
|
142
|
+
'<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M14.76 12H6.832m0 0c0-.275-.057-.55-.17-.808L4.285 5.814c-.76-1.72 1.058-3.442 2.734-2.591L20.8 10.217c1.46.74 1.46 2.826 0 3.566L7.02 20.777c-1.677.851-3.495-.872-2.735-2.591l2.375-5.378A2 2 0 0 0 6.83 12"/></svg>'}
|
|
143
|
+
</div>
|
|
144
|
+
<p class="font-bold">{device.DevName}</p>
|
|
145
|
+
</div>
|
|
146
|
+
{/snippet}
|
|
147
|
+
<Popup closeButton={false} class="rounded-2xl text-left">
|
|
148
|
+
<p>DevSN: {device.DevSN}</p>
|
|
149
|
+
<p>Lat: {`${device.NavLat.toFixed(3)} | Lon: ${device.NavLon.toFixed(3)} | Alt: ${device.NavAlt}`}</p>
|
|
150
|
+
<p>Heading: {device.NavHeading} | Sat Use: {device.NavSatUse}</p>
|
|
151
|
+
|
|
152
|
+
<div class="relative flex justify-between">
|
|
153
|
+
<button
|
|
154
|
+
class="absolute right-0 flex cursor-pointer border-none bg-transparent"
|
|
155
|
+
onclick={(e) => {
|
|
156
|
+
e.preventDefault()
|
|
157
|
+
navigator.clipboard.writeText(
|
|
158
|
+
`DevName: ${device.DevName}\nDevSN: ${device.DevSN}\nLat: ${device.NavLat.toFixed(3)} | Lon: ${device.NavLon.toFixed(3)} | Alt: ${device.NavAlt}\nHeading: ${device.NavHeading} | Sat Use: ${device.NavSatUse}`,
|
|
159
|
+
)
|
|
160
|
+
isCopied = true
|
|
161
|
+
setTimeout(() => (isCopied = false), 1000)
|
|
162
|
+
}}
|
|
163
|
+
aria-label="Копировать текст"
|
|
164
|
+
>
|
|
165
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="1.5rem" height="1.5rem" viewBox="0 0 24 24">
|
|
166
|
+
<g fill="none" stroke="currentColor" stroke-width="1.5">
|
|
167
|
+
<path
|
|
168
|
+
d="M6 11c0-2.828 0-4.243.879-5.121C7.757 5 9.172 5 12 5h3c2.828 0 4.243 0 5.121.879C21 6.757 21 8.172 21 11v5c0 2.828 0 4.243-.879 5.121C19.243 22 17.828 22 15 22h-3c-2.828 0-4.243 0-5.121-.879C6 20.243 6 18.828 6 16z"
|
|
169
|
+
/>
|
|
170
|
+
<path d="M6 19a3 3 0 0 1-3-3v-6c0-3.771 0-5.657 1.172-6.828S7.229 2 11 2h4a3 3 0 0 1 3 3" />
|
|
171
|
+
</g>
|
|
172
|
+
</svg>
|
|
173
|
+
</button>
|
|
174
|
+
{#if isCopied}
|
|
175
|
+
<div
|
|
176
|
+
class="absolute top-1/2 right-0 -translate-y-1/2 transform rounded-md bg-(--green-color) px-2 py-1 text-sm shadow-lg"
|
|
177
|
+
transition:fade={{ duration: 200 }}
|
|
178
|
+
>
|
|
179
|
+
✓
|
|
180
|
+
</div>
|
|
181
|
+
{/if}
|
|
182
|
+
|
|
183
|
+
<button
|
|
184
|
+
class="size-6 cursor-pointer"
|
|
185
|
+
aria-label="Удалить"
|
|
186
|
+
onclick={() => (devices = devices.filter((dev) => dev.DevSN !== device.DevSN))}
|
|
187
|
+
>
|
|
188
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="1.5rem" height="1.5rem" viewBox="0 0 24 24"
|
|
189
|
+
><path
|
|
190
|
+
fill="none"
|
|
191
|
+
stroke="currentColor"
|
|
192
|
+
stroke-linecap="round"
|
|
193
|
+
stroke-linejoin="round"
|
|
194
|
+
stroke-width="1.5"
|
|
195
|
+
d="m19.5 5.5l-.62 10.025c-.158 2.561-.237 3.842-.88 4.763a4 4 0 0 1-1.2 1.128c-.957.584-2.24.584-4.806.584c-2.57 0-3.855 0-4.814-.585a4 4 0 0 1-1.2-1.13c-.642-.922-.72-2.205-.874-4.77L4.5 5.5M3 5.5h18m-4.944 0l-.683-1.408c-.453-.936-.68-1.403-1.071-1.695a2 2 0 0 0-.275-.172C13.594 2 13.074 2 12.035 2c-1.066 0-1.599 0-2.04.234a2 2 0 0 0-.278.18c-.395.303-.616.788-1.058 1.757L8.053 5.5m1.447 11v-6m5 6v-6"
|
|
196
|
+
color="currentColor"
|
|
197
|
+
/></svg
|
|
198
|
+
>
|
|
199
|
+
</button>
|
|
200
|
+
</div>
|
|
201
|
+
</Popup>
|
|
202
|
+
</Marker>
|
|
203
|
+
{/each}
|
|
204
|
+
</MapLibre>
|
|
205
|
+
</div>
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { getContext } from 'svelte'
|
|
3
|
+
import { t } from '../locales/i18n'
|
|
4
|
+
import { type UIComponent, type IGraphProps, updateProperty } from '../types'
|
|
5
|
+
import * as UI from '..'
|
|
6
|
+
import Modal from '../Modal.svelte'
|
|
7
|
+
import { ICONS } from '../icons'
|
|
8
|
+
import Button from '../Button/Button.svelte'
|
|
9
|
+
import CrossIcon from '../libIcons/CrossIcon.svelte'
|
|
10
|
+
|
|
11
|
+
const {
|
|
12
|
+
component,
|
|
13
|
+
onPropertyChange,
|
|
14
|
+
forConstructor = true,
|
|
15
|
+
} = $props<{
|
|
16
|
+
component: UIComponent & { properties: Partial<IGraphProps> }
|
|
17
|
+
onPropertyChange: (value?: string | object, name?: string, access?: string) => void
|
|
18
|
+
forConstructor?: boolean
|
|
19
|
+
}>()
|
|
20
|
+
|
|
21
|
+
let showIconLib = $state(false)
|
|
22
|
+
|
|
23
|
+
const DeviceVariables = getContext<{ id: string; value: string; name: string }[]>('DeviceVariables')
|
|
24
|
+
let VARIABLE_OPTIONS = $derived(DeviceVariables && Array.isArray(DeviceVariables) ? DeviceVariables : [])
|
|
25
|
+
</script>
|
|
26
|
+
|
|
27
|
+
{#if forConstructor}
|
|
28
|
+
<div class="relative flex flex-row items-start justify-center">
|
|
29
|
+
<!-- Сообщение для отправки в ws по нажатию кнопки -->
|
|
30
|
+
<div class="flex w-1/3 flex-col items-center px-2">
|
|
31
|
+
<UI.Select
|
|
32
|
+
label={{ name: $t('constructor.props.variable') }}
|
|
33
|
+
options={VARIABLE_OPTIONS}
|
|
34
|
+
value={VARIABLE_OPTIONS.find((opt) => opt.value === component.properties.id)}
|
|
35
|
+
onUpdate={(value) => {
|
|
36
|
+
updateProperty('id', value.value as string, component, onPropertyChange)
|
|
37
|
+
updateProperty('eventHandler.Variables', value.value as string, component, onPropertyChange)
|
|
38
|
+
onPropertyChange(null, value.name?.split('—')[1].trim(), null)
|
|
39
|
+
}}
|
|
40
|
+
/>
|
|
41
|
+
</div>
|
|
42
|
+
<div class="flex w-1/3 flex-col px-2">
|
|
43
|
+
<UI.Input
|
|
44
|
+
label={{ name: $t('constructor.props.label') }}
|
|
45
|
+
value={component.properties.label.name}
|
|
46
|
+
onUpdate={(value) => updateProperty('label.name', value as string, component, onPropertyChange)}
|
|
47
|
+
/>
|
|
48
|
+
<UI.Input
|
|
49
|
+
label={{ name: $t('constructor.props.label.class') }}
|
|
50
|
+
value={component.properties.label.class}
|
|
51
|
+
onUpdate={(value) => updateProperty('label.class', value as string, component, onPropertyChange)}
|
|
52
|
+
/>
|
|
53
|
+
</div>
|
|
54
|
+
<div class="flex w-1/3 flex-col px-2">
|
|
55
|
+
<div class="mt-6 flex gap-2">
|
|
56
|
+
<UI.Button content={{ name: $t('constructor.props.markerIcon') }} onClick={() => (showIconLib = true)} />
|
|
57
|
+
{#if showIconLib}
|
|
58
|
+
<Modal bind:isOpen={showIconLib} wrapperClass="w-130">
|
|
59
|
+
{#snippet main()}
|
|
60
|
+
<div class="grid grid-cols-3">
|
|
61
|
+
{#each ICONS as category}
|
|
62
|
+
<div class="relative m-1.5 rounded-xl border-2 border-(--border-color) p-3">
|
|
63
|
+
<div class="absolute -top-3.5 bg-(--back-color) px-1">{$t(`constructor.props.icon.${category[0]}`)}</div>
|
|
64
|
+
<div class="grid grid-cols-3 place-items-center gap-2">
|
|
65
|
+
{#each category[1] as icon}
|
|
66
|
+
<button
|
|
67
|
+
class="h-8 w-8 cursor-pointer [&_svg]:h-full [&_svg]:max-h-full [&_svg]:w-full [&_svg]:max-w-full"
|
|
68
|
+
onclick={() => {
|
|
69
|
+
updateProperty('markerIcon', icon as string, component, onPropertyChange)
|
|
70
|
+
}}
|
|
71
|
+
>
|
|
72
|
+
{@html icon}
|
|
73
|
+
</button>{/each}
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
{/each}
|
|
77
|
+
</div>
|
|
78
|
+
{/snippet}
|
|
79
|
+
</Modal>
|
|
80
|
+
{/if}
|
|
81
|
+
{#if component.properties.markerIcon}
|
|
82
|
+
<Button
|
|
83
|
+
wrapperClass="w-8.5 "
|
|
84
|
+
componentClass="p-0.5 bg-red"
|
|
85
|
+
content={{ icon: CrossIcon }}
|
|
86
|
+
onClick={() => {
|
|
87
|
+
updateProperty('markerIcon', '', component, onPropertyChange)
|
|
88
|
+
}}
|
|
89
|
+
/>
|
|
90
|
+
{/if}
|
|
91
|
+
</div>
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
{:else}
|
|
95
|
+
<div class="relative mb-2 flex flex-row items-start justify-center">
|
|
96
|
+
<!-- Сообщение для отправки в ws по нажатию кнопки -->
|
|
97
|
+
<div class="flex w-1/3 flex-col items-center px-2">
|
|
98
|
+
<UI.Input
|
|
99
|
+
label={{ name: $t('constructor.props.id') }}
|
|
100
|
+
value={component.properties.id}
|
|
101
|
+
onUpdate={(value) => updateProperty('id', value as string, component, onPropertyChange)}
|
|
102
|
+
/>
|
|
103
|
+
</div>
|
|
104
|
+
<div class="flex w-1/3 flex-col px-2">
|
|
105
|
+
<UI.Input
|
|
106
|
+
label={{ name: $t('constructor.props.label') }}
|
|
107
|
+
value={component.properties.label.name}
|
|
108
|
+
onUpdate={(value) => updateProperty('label.name', value as string, component, onPropertyChange)}
|
|
109
|
+
/>
|
|
110
|
+
<UI.Input
|
|
111
|
+
label={{ name: $t('constructor.props.label.class') }}
|
|
112
|
+
value={component.properties.label.class}
|
|
113
|
+
onUpdate={(value) => updateProperty('label.class', value as string, component, onPropertyChange)}
|
|
114
|
+
/>
|
|
115
|
+
</div>
|
|
116
|
+
|
|
117
|
+
<div class="flex w-1/3 flex-col px-2">
|
|
118
|
+
<div class="mt-6 flex gap-2">
|
|
119
|
+
<UI.Button content={{ name: $t('constructor.props.markerIcon') }} onClick={() => (showIconLib = true)} />
|
|
120
|
+
{#if showIconLib}
|
|
121
|
+
<Modal bind:isOpen={showIconLib} wrapperClass="w-130">
|
|
122
|
+
{#snippet main()}
|
|
123
|
+
<div class="grid grid-cols-3">
|
|
124
|
+
{#each ICONS as category}
|
|
125
|
+
<div class="relative m-1.5 rounded-xl border-2 border-(--border-color) p-3">
|
|
126
|
+
<div class="absolute -top-3.5 bg-(--back-color) px-1">{$t(`constructor.props.icon.${category[0]}`)}</div>
|
|
127
|
+
<div class="grid grid-cols-3 place-items-center gap-2">
|
|
128
|
+
{#each category[1] as icon}
|
|
129
|
+
<button
|
|
130
|
+
class="h-8 w-8 cursor-pointer [&_svg]:h-full [&_svg]:max-h-full [&_svg]:w-full [&_svg]:max-w-full"
|
|
131
|
+
onclick={() => {
|
|
132
|
+
updateProperty('markerIcon', icon as string, component, onPropertyChange)
|
|
133
|
+
}}
|
|
134
|
+
>
|
|
135
|
+
{@html icon}
|
|
136
|
+
</button>{/each}
|
|
137
|
+
</div>
|
|
138
|
+
</div>
|
|
139
|
+
{/each}
|
|
140
|
+
</div>
|
|
141
|
+
{/snippet}
|
|
142
|
+
</Modal>
|
|
143
|
+
{/if}
|
|
144
|
+
{#if component.properties.markerIcon}
|
|
145
|
+
<Button
|
|
146
|
+
wrapperClass="w-8.5 "
|
|
147
|
+
componentClass="p-0.5 bg-red"
|
|
148
|
+
content={{ icon: CrossIcon }}
|
|
149
|
+
onClick={() => {
|
|
150
|
+
updateProperty('markerIcon', '', component, onPropertyChange)
|
|
151
|
+
}}
|
|
152
|
+
/>
|
|
153
|
+
{/if}
|
|
154
|
+
</div>
|
|
155
|
+
</div>
|
|
156
|
+
</div>
|
|
157
|
+
{/if}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type UIComponent, type IGraphProps } from '../types';
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
component: UIComponent & {
|
|
4
|
+
properties: Partial<IGraphProps>;
|
|
5
|
+
};
|
|
6
|
+
onPropertyChange: (value?: string | object, name?: string, access?: string) => void;
|
|
7
|
+
forConstructor?: boolean;
|
|
8
|
+
};
|
|
9
|
+
declare const MapProps: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
10
|
+
type MapProps = ReturnType<typeof MapProps>;
|
|
11
|
+
export default MapProps;
|
|
@@ -144,9 +144,12 @@
|
|
|
144
144
|
number={{ minNum: 0, maxNum: 31, step: 1 }}
|
|
145
145
|
value={[component.properties.range.start, component.properties.range.end]}
|
|
146
146
|
onUpdate={(value) => {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
147
|
+
if (Array.isArray(value)) {
|
|
148
|
+
if (value[1] - value[0] > 6) value = [value[0], value[0] + 6]
|
|
149
|
+
updateProperty('range.start', value[0] as number, component, onPropertyChange)
|
|
150
|
+
updateProperty('range.end', value[1] as number, component, onPropertyChange)
|
|
151
|
+
generateBitOptions(component.properties.range.start, component.properties.range.end)
|
|
152
|
+
}
|
|
150
153
|
}}
|
|
151
154
|
/>
|
|
152
155
|
{/if}
|
|
@@ -25,6 +25,10 @@
|
|
|
25
25
|
let lowerValue = $derived(isRange && Array.isArray(value) ? value[0] : number.minNum)
|
|
26
26
|
let upperValue = $derived(isRange && Array.isArray(value) ? value[1] : number.maxNum)
|
|
27
27
|
|
|
28
|
+
let activeRound: 'floor' | 'ceil' = $state('floor')
|
|
29
|
+
|
|
30
|
+
let centerNum = $derived(lowerValue + Math[activeRound]((upperValue - lowerValue) / 2 / number.step) * number.step)
|
|
31
|
+
|
|
28
32
|
$effect(() => {
|
|
29
33
|
if (value === undefined || value === null) {
|
|
30
34
|
if (type === 'single' && !value) value = number.minNum
|
|
@@ -36,15 +40,15 @@
|
|
|
36
40
|
const stepValue = direction === 'increment' ? number.step : -number.step
|
|
37
41
|
if (isRange && target !== 'single') {
|
|
38
42
|
if (target === 'lower') {
|
|
39
|
-
lowerValue = Math.max(number.minNum, Math.min(lowerValue + stepValue, upperValue))
|
|
40
|
-
lowerValue = lowerValue == upperValue ? upperValue - number.step : lowerValue
|
|
43
|
+
lowerValue = roundToClean(Math.max(number.minNum, Math.min(lowerValue + stepValue, upperValue)))
|
|
44
|
+
lowerValue = roundToClean(lowerValue == upperValue ? upperValue - number.step : lowerValue)
|
|
41
45
|
} else {
|
|
42
|
-
upperValue = Math.min(number.maxNum, Math.max(upperValue + stepValue, lowerValue))
|
|
43
|
-
upperValue = upperValue == lowerValue ? upperValue + number.step : upperValue
|
|
46
|
+
upperValue = roundToClean(Math.min(number.maxNum, Math.max(upperValue + stepValue, lowerValue)))
|
|
47
|
+
upperValue = roundToClean(upperValue == lowerValue ? upperValue + number.step : upperValue)
|
|
44
48
|
}
|
|
45
49
|
onUpdate([lowerValue, upperValue])
|
|
46
50
|
} else {
|
|
47
|
-
singleValue = Math.max(number.minNum, Math.min(singleValue + stepValue, number.maxNum))
|
|
51
|
+
singleValue = roundToClean(Math.max(number.minNum, Math.min(singleValue + stepValue, number.maxNum)))
|
|
48
52
|
onUpdate(singleValue)
|
|
49
53
|
}
|
|
50
54
|
}
|
|
@@ -58,79 +62,17 @@
|
|
|
58
62
|
}
|
|
59
63
|
})
|
|
60
64
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
e.stopPropagation()
|
|
64
|
-
const track = e.currentTarget as HTMLElement
|
|
65
|
-
const rect = track.getBoundingClientRect()
|
|
66
|
-
const clickPercent = ((e.clientX - rect.left) / rect.width) * 100
|
|
67
|
-
const rawValue = number.minNum + (clickPercent / 100) * (number.maxNum - number.minNum)
|
|
68
|
-
const clickValue = Math.round((rawValue - number.minNum) / number.step) * number.step + number.minNum
|
|
69
|
-
|
|
70
|
-
if (isRange) {
|
|
71
|
-
const lowerDiff = Math.abs(clickValue - lowerValue)
|
|
72
|
-
const upperDiff = Math.abs(clickValue - upperValue)
|
|
73
|
-
|
|
74
|
-
activeThumb = lowerDiff < upperDiff ? 'lower' : 'upper'
|
|
75
|
-
|
|
76
|
-
if (activeThumb === 'lower') {
|
|
77
|
-
lowerValue = Math.max(number.minNum, Math.min(clickValue, upperValue))
|
|
78
|
-
lowerValue = lowerValue == upperValue ? upperValue - number.step : lowerValue
|
|
79
|
-
} else {
|
|
80
|
-
upperValue = Math.min(number.maxNum, Math.max(clickValue, lowerValue))
|
|
81
|
-
upperValue = upperValue == lowerValue ? upperValue + number.step : upperValue
|
|
82
|
-
}
|
|
83
|
-
onUpdate([lowerValue, upperValue])
|
|
84
|
-
} else {
|
|
85
|
-
singleValue = Math.max(number.minNum, Math.min(clickValue, number.maxNum))
|
|
86
|
-
onUpdate(singleValue)
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
let rangeRefLower: HTMLElement | null = $state(null)
|
|
91
|
-
let rangeRefUpper: HTMLElement | null = $state(null)
|
|
92
|
-
let shadowWidth = $state()
|
|
65
|
+
const roundToClean = (num: number): number => {
|
|
66
|
+
if (Number.isInteger(num)) return num
|
|
93
67
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
let thumbCenterUpper
|
|
68
|
+
const rounded1 = Number(num.toFixed(1))
|
|
69
|
+
if (Math.abs(rounded1 - num) < 1e-10) return rounded1
|
|
97
70
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
const percent = (lowerValue - number.minNum) / (number.maxNum - number.minNum)
|
|
101
|
-
thumbCenterLower = rect.left + rect.width * percent
|
|
102
|
-
}
|
|
71
|
+
const rounded2 = Number(num.toFixed(2))
|
|
72
|
+
if (Math.abs(rounded2 - num) < 1e-10) return rounded2
|
|
103
73
|
|
|
104
|
-
|
|
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
|
-
}
|
|
74
|
+
return rounded2
|
|
113
75
|
}
|
|
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
|
-
})
|
|
134
76
|
</script>
|
|
135
77
|
|
|
136
78
|
<div class={twMerge(`bg-blue relative flex w-full flex-col items-center `, wrapperClass)}>
|
|
@@ -141,57 +83,42 @@
|
|
|
141
83
|
<!-- Слайдер -->
|
|
142
84
|
<div
|
|
143
85
|
id={`${id}-${crypto.randomUUID().slice(0, 6)}`}
|
|
144
|
-
class="relative flex h-
|
|
86
|
+
class="relative flex h-8 w-full items-center justify-center rounded-full {disabled ? 'cursor-not-allowed opacity-50' : ''}"
|
|
145
87
|
>
|
|
146
88
|
{#if isRange}
|
|
147
89
|
{@const userAgent = navigator.userAgent}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
disabled
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
? undefined
|
|
169
|
-
: (e) => {
|
|
170
|
-
const newValue = Math.min(Number((e.target as HTMLInputElement).value), upperValue)
|
|
171
|
-
lowerValue = newValue
|
|
172
|
-
lowerValue = newValue == upperValue ? upperValue - number.step : newValue
|
|
173
|
-
}}
|
|
174
|
-
onmouseup={(e) => {
|
|
175
|
-
handleTrackClick(e)
|
|
176
|
-
disabled ? undefined : () => onUpdate([lowerValue, upperValue])
|
|
177
|
-
}}
|
|
178
|
-
{disabled}
|
|
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
|
|
90
|
+
<div class="flex w-full">
|
|
91
|
+
<input
|
|
92
|
+
type="range"
|
|
93
|
+
min={number.minNum}
|
|
94
|
+
max={centerNum}
|
|
95
|
+
step={number.step}
|
|
96
|
+
bind:value={lowerValue}
|
|
97
|
+
oninput={disabled
|
|
98
|
+
? undefined
|
|
99
|
+
: (e) => {
|
|
100
|
+
const newValue = Math.min(Number((e.target as HTMLInputElement).value), upperValue)
|
|
101
|
+
lowerValue = roundToClean(newValue == upperValue ? upperValue - number.step : newValue)
|
|
102
|
+
onUpdate([lowerValue, upperValue])
|
|
103
|
+
}}
|
|
104
|
+
onmousedown={() => (activeRound = 'ceil')}
|
|
105
|
+
{disabled}
|
|
106
|
+
class={twMerge(
|
|
107
|
+
`slider-bg basis-[calc(${(centerNum / number.maxNum) * 100}%+2rem+5px)] h-8 w-full appearance-none overflow-hidden
|
|
108
|
+
accent-(--back-color)
|
|
109
|
+
[&::-webkit-slider-runnable-track]:rounded-l-full
|
|
182
110
|
[&::-webkit-slider-runnable-track]:bg-(--gray-color)
|
|
183
|
-
[&::-webkit-slider-
|
|
184
|
-
[&::-webkit-slider-thumb]:
|
|
185
|
-
[&::-webkit-slider-thumb]:
|
|
186
|
-
[&::-webkit-slider-thumb]:
|
|
187
|
-
[&::-webkit-slider-thumb]:w-4
|
|
111
|
+
[&::-webkit-slider-runnable-track]:px-2
|
|
112
|
+
[&::-webkit-slider-thumb]:relative
|
|
113
|
+
[&::-webkit-slider-thumb]:z-100
|
|
114
|
+
[&::-webkit-slider-thumb]:size-4
|
|
188
115
|
[&::-webkit-slider-thumb]:cursor-pointer
|
|
189
116
|
[&::-webkit-slider-thumb]:rounded-full
|
|
190
|
-
|
|
117
|
+
[&::-webkit-slider-thumb]:shadow-[var(--focus-shadow),]
|
|
191
118
|
${
|
|
192
119
|
userAgent.includes('iOS') || userAgent.includes('iPhone') || userAgent.includes('iPad')
|
|
193
|
-
? '
|
|
194
|
-
: '
|
|
120
|
+
? '[&::-webkit-slider-thumb]:ring-[6.5px]'
|
|
121
|
+
: '[&::-webkit-slider-thumb]:ring-[5px] '
|
|
195
122
|
}
|
|
196
123
|
[&::-moz-range-thumb]:relative
|
|
197
124
|
[&::-moz-range-thumb]:ml-[-0.4rem]
|
|
@@ -203,45 +130,42 @@
|
|
|
203
130
|
[&::-moz-range-track]:rounded-full
|
|
204
131
|
[&::-moz-range-track]:bg-(--gray-color)
|
|
205
132
|
`,
|
|
206
|
-
|
|
207
|
-
[&::-webkit-slider-thumb]:shadow-[calc(
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
[&::-webkit-slider-
|
|
233
|
-
[&::-webkit-slider-thumb]:relative
|
|
133
|
+
`[&::-moz-range-thumb]:shadow-[calc(100rem+0.5rem)_0_0_100rem]
|
|
134
|
+
[&::-webkit-slider-thumb]:shadow-[calc(100rem+0.5rem)_0_0_100rem]`,
|
|
135
|
+
)}
|
|
136
|
+
style={`flex-basis: calc(${(centerNum / number.maxNum) * 100}%+2rem+5px)`}
|
|
137
|
+
/>
|
|
138
|
+
<input
|
|
139
|
+
type="range"
|
|
140
|
+
min={centerNum}
|
|
141
|
+
max={number.maxNum}
|
|
142
|
+
step={number.step}
|
|
143
|
+
bind:value={upperValue}
|
|
144
|
+
oninput={disabled
|
|
145
|
+
? undefined
|
|
146
|
+
: (e) => {
|
|
147
|
+
const newValue = Math.max(Number((e.target as HTMLInputElement).value), lowerValue)
|
|
148
|
+
upperValue = roundToClean(newValue == lowerValue ? newValue + number.step : upperValue)
|
|
149
|
+
onUpdate([lowerValue, upperValue])
|
|
150
|
+
}}
|
|
151
|
+
onmousedown={() => (activeRound = 'floor')}
|
|
152
|
+
{disabled}
|
|
153
|
+
class={twMerge(
|
|
154
|
+
`slider-bg basis-[calc(${100 - (centerNum / number.maxNum) * 100}%+2rem+5px)] h-8 w-full appearance-none overflow-hidden
|
|
155
|
+
accent-(--back-color)
|
|
156
|
+
[&::-webkit-slider-runnable-track]:rounded-r-full
|
|
157
|
+
[&::-webkit-slider-runnable-track]:bg-(--gray-color)
|
|
158
|
+
[&::-webkit-slider-runnable-track]:px-2
|
|
159
|
+
[&::-webkit-slider-thumb]:relative
|
|
234
160
|
[&::-webkit-slider-thumb]:z-100
|
|
235
|
-
[&::-webkit-slider-thumb]:
|
|
236
|
-
[&::-webkit-slider-thumb]:h-4
|
|
237
|
-
[&::-webkit-slider-thumb]:w-4
|
|
161
|
+
[&::-webkit-slider-thumb]:size-4
|
|
238
162
|
[&::-webkit-slider-thumb]:cursor-pointer
|
|
239
163
|
[&::-webkit-slider-thumb]:rounded-full
|
|
240
|
-
|
|
164
|
+
[&::-webkit-slider-thumb]:shadow-[var(--focus-shadow),]
|
|
241
165
|
${
|
|
242
166
|
userAgent.includes('iOS') || userAgent.includes('iPhone') || userAgent.includes('iPad')
|
|
243
|
-
? '
|
|
244
|
-
: '
|
|
167
|
+
? '[&::-webkit-slider-thumb]:ring-[6.5px]'
|
|
168
|
+
: '[&::-webkit-slider-thumb]:ring-[5px] '
|
|
245
169
|
}
|
|
246
170
|
[&::-moz-range-thumb]:relative
|
|
247
171
|
[&::-moz-range-thumb]:ml-[-0.4rem]
|
|
@@ -253,16 +177,23 @@
|
|
|
253
177
|
[&::-moz-range-track]:rounded-full
|
|
254
178
|
[&::-moz-range-track]:bg-(--gray-color)
|
|
255
179
|
`,
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
180
|
+
`[&::-moz-range-thumb]:shadow-[calc(100rem*-1-0.5rem)_0_0_100rem]
|
|
181
|
+
[&::-webkit-slider-thumb]:shadow-[calc(100rem*-1-0.5rem)_0_0_100rem]`,
|
|
182
|
+
)}
|
|
183
|
+
style={`flex-basis: calc(${(centerNum / number.maxNum) * 100}%+2rem+5px)`}
|
|
184
|
+
/>
|
|
185
|
+
</div>
|
|
260
186
|
{:else}
|
|
261
187
|
{@const userAgent = navigator.userAgent}
|
|
262
188
|
<!-- Одиночный слайдер -->
|
|
263
189
|
<div class="absolute h-full w-full">
|
|
264
190
|
<input
|
|
265
191
|
type="range"
|
|
192
|
+
min={number.minNum}
|
|
193
|
+
max={number.maxNum}
|
|
194
|
+
step={number.step}
|
|
195
|
+
bind:value={singleValue}
|
|
196
|
+
oninput={() => onUpdate(singleValue)}
|
|
266
197
|
class={twMerge(
|
|
267
198
|
`slider-bg h-8 w-full appearance-none overflow-hidden rounded-full accent-(--back-color)
|
|
268
199
|
[&::-webkit-slider-runnable-track]:rounded-full
|
|
@@ -293,10 +224,6 @@
|
|
|
293
224
|
`[&::-moz-range-thumb]:shadow-[calc(100rem*-1-0.5rem)_0_0_100rem]
|
|
294
225
|
[&::-webkit-slider-thumb]:shadow-[calc(100rem*-1-0.5rem)_0_0_100rem]`,
|
|
295
226
|
)}
|
|
296
|
-
min={number.minNum}
|
|
297
|
-
max={number.maxNum}
|
|
298
|
-
step={number.step}
|
|
299
|
-
bind:value={singleValue}
|
|
300
227
|
/>
|
|
301
228
|
</div>
|
|
302
229
|
{/if}
|
package/dist/index.d.ts
CHANGED
|
@@ -12,6 +12,8 @@ export { default as InputProps } from './Input/InputProps.svelte';
|
|
|
12
12
|
export { default as Joystick } from './Joystick/Joystick.svelte';
|
|
13
13
|
export { default as JoystickProps } from './Joystick/JoystickProps.svelte';
|
|
14
14
|
export { default as Modal } from './Modal.svelte';
|
|
15
|
+
export { default as Map } from './Map/Map.svelte';
|
|
16
|
+
export { default as MapProps } from './Map/MapProps.svelte';
|
|
15
17
|
export { default as ProgressBar } from './ProgressBar/ProgressBar.svelte';
|
|
16
18
|
export { default as ProgressBarProps } from './ProgressBar/ProgressBarProps.svelte';
|
|
17
19
|
export { default as Select } from './Select/Select.svelte';
|
|
@@ -28,4 +30,4 @@ export { default as TextField } from './TextField/TextField.svelte';
|
|
|
28
30
|
export { default as TextFieldProps } from './TextField/TextFieldProps.svelte';
|
|
29
31
|
export * from './locales/i18n';
|
|
30
32
|
export * from './locales/translations';
|
|
31
|
-
export { type UIComponent, type Position, type IUIComponentHandler, type IButtonProps, type IAccordionProps, type IInputProps, type ISelectProps, type ISelectOption, type ISwitchProps, type IColorPickerProps, type ISliderProps, type ITextFieldProps, type IProgressBarProps, type IGraphProps, type IGraphDataObject, type ITableHeader, type ITableProps, type ITabsProps, type IJoystickProps, } from './types';
|
|
33
|
+
export { type UIComponent, type Position, type IUIComponentHandler, type IButtonProps, type IAccordionProps, type IInputProps, type ISelectProps, type ISelectOption, type ISwitchProps, type IColorPickerProps, type ISliderProps, type ITextFieldProps, type IMapProps, type IProgressBarProps, type IGraphProps, type IGraphDataObject, type ITableHeader, type ITableProps, type ITabsProps, type IJoystickProps, } from './types';
|
package/dist/index.js
CHANGED
|
@@ -13,6 +13,8 @@ export { default as InputProps } from './Input/InputProps.svelte';
|
|
|
13
13
|
export { default as Joystick } from './Joystick/Joystick.svelte';
|
|
14
14
|
export { default as JoystickProps } from './Joystick/JoystickProps.svelte';
|
|
15
15
|
export { default as Modal } from './Modal.svelte';
|
|
16
|
+
export { default as Map } from './Map/Map.svelte';
|
|
17
|
+
export { default as MapProps } from './Map/MapProps.svelte';
|
|
16
18
|
export { default as ProgressBar } from './ProgressBar/ProgressBar.svelte';
|
|
17
19
|
export { default as ProgressBarProps } from './ProgressBar/ProgressBarProps.svelte';
|
|
18
20
|
export { default as Select } from './Select/Select.svelte';
|
|
@@ -72,6 +72,7 @@ const translations = {
|
|
|
72
72
|
'constructor.props.align.content': 'Выравнивание контента',
|
|
73
73
|
'constructor.props.image': 'Фоновое изображение',
|
|
74
74
|
'constructor.props.labelicon': 'Иконка заголовка',
|
|
75
|
+
'constructor.props.markerIcon': 'Иконка маркера',
|
|
75
76
|
'constructor.props.removeimage': 'Удалить изображение',
|
|
76
77
|
'constructor.props.name': 'Текст',
|
|
77
78
|
'constructor.props.height': 'Высота',
|
|
@@ -125,6 +126,7 @@ const translations = {
|
|
|
125
126
|
'constructor.props.equal': 'Равные',
|
|
126
127
|
'constructor.props.bitmode': 'Битовый режим',
|
|
127
128
|
'constructor.props.access': 'Доступ (не для владельца)',
|
|
129
|
+
'constructor.props.map.timeout': 'Таймаут маркеров:',
|
|
128
130
|
'constructor.props.table.columns': 'Колонки таблицы',
|
|
129
131
|
'constructor.props.table.columns.key': 'Ключ',
|
|
130
132
|
'constructor.props.table.columns.label': 'Название колонки',
|
package/dist/types.d.ts
CHANGED
|
@@ -8,8 +8,8 @@ export interface UIComponent {
|
|
|
8
8
|
id: string;
|
|
9
9
|
name?: string;
|
|
10
10
|
access?: 'full' | 'viewOnly' | 'hidden';
|
|
11
|
-
type: 'Button' | 'Accordion' | 'Input' | 'Select' | 'Switch' | 'ColorPicker' | 'Slider' | 'TextField' | 'Joystick' | 'ProgressBar' | 'Graph' | 'Table' | 'Tabs' | 'FileAttach';
|
|
12
|
-
properties: IAccordionProps | IButtonProps | IInputProps | ISelectProps | ISwitchProps | IColorPickerProps | ISliderProps | ITextFieldProps | IProgressBarProps | IGraphProps | ITableProps<object> | ITabsProps | IFileInputProps | IJoystickProps;
|
|
11
|
+
type: 'Button' | 'Accordion' | 'Input' | 'Select' | 'Switch' | 'ColorPicker' | 'Slider' | 'TextField' | 'Joystick' | 'ProgressBar' | 'Graph' | 'Table' | 'Tabs' | 'FileAttach' | 'Map';
|
|
12
|
+
properties: IAccordionProps | IButtonProps | IInputProps | ISelectProps | ISwitchProps | IColorPickerProps | ISliderProps | ITextFieldProps | IProgressBarProps | IGraphProps | ITableProps<object> | ITabsProps | IFileInputProps | IJoystickProps | IMapProps;
|
|
13
13
|
position: Position;
|
|
14
14
|
parentId: string;
|
|
15
15
|
}
|
|
@@ -298,3 +298,21 @@ export interface IJoystickProps {
|
|
|
298
298
|
}[];
|
|
299
299
|
onUpdate?: (value: number[]) => void;
|
|
300
300
|
}
|
|
301
|
+
export interface IDeviceGNSS {
|
|
302
|
+
NavLat: number;
|
|
303
|
+
NavLon: number;
|
|
304
|
+
NavAlt: number;
|
|
305
|
+
DevName: string;
|
|
306
|
+
DevSN: string;
|
|
307
|
+
NavHeading: number;
|
|
308
|
+
NavSatUse: number;
|
|
309
|
+
}
|
|
310
|
+
export interface IMapProps {
|
|
311
|
+
id?: string;
|
|
312
|
+
label?: {
|
|
313
|
+
name?: string;
|
|
314
|
+
class?: string;
|
|
315
|
+
};
|
|
316
|
+
data: IDeviceGNSS | null;
|
|
317
|
+
markerIcon?: string;
|
|
318
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "poe-svelte-ui-lib",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.28",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"prettier": "^3.6.2",
|
|
37
37
|
"prettier-plugin-svelte": "^3.4.0",
|
|
38
38
|
"prettier-plugin-tailwindcss": "^0.7.1",
|
|
39
|
+
"svelte-maplibre-gl": "^1.0.2",
|
|
39
40
|
"tailwind-merge": "^3.4.0",
|
|
40
41
|
"tailwindcss": "^4.1.17",
|
|
41
42
|
"tsx": "^4.20.6",
|
|
@@ -43,14 +44,14 @@
|
|
|
43
44
|
},
|
|
44
45
|
"devDependencies": {
|
|
45
46
|
"@sveltejs/adapter-static": "^3.0.10",
|
|
46
|
-
"@sveltejs/kit": "^2.
|
|
47
|
-
"@sveltejs/package": "^2.5.
|
|
47
|
+
"@sveltejs/kit": "^2.49.0",
|
|
48
|
+
"@sveltejs/package": "^2.5.6",
|
|
48
49
|
"@sveltejs/vite-plugin-svelte": "^6.2.1",
|
|
49
50
|
"@types/node": "^24.10.1",
|
|
50
51
|
"publint": "^0.3.15",
|
|
51
|
-
"svelte": "^5.43.
|
|
52
|
+
"svelte": "^5.43.14",
|
|
52
53
|
"svelte-preprocess": "^6.0.3",
|
|
53
|
-
"vite": "^7.2.
|
|
54
|
+
"vite": "^7.2.4",
|
|
54
55
|
"vite-plugin-compression": "^0.5.1"
|
|
55
56
|
}
|
|
56
57
|
}
|