poe-svelte-ui-lib 1.0.6 → 1.0.8
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/Accordion/Accordion.svelte +51 -40
- package/dist/Accordion/AccordionProps.svelte +76 -0
- package/dist/Accordion/AccordionProps.svelte.d.ts +10 -0
- package/dist/Button/Button.svelte +28 -34
- package/dist/Button/ButtonProps.svelte +113 -0
- package/dist/Button/ButtonProps.svelte.d.ts +10 -0
- package/dist/ColorPicker/ColorPicker.svelte +27 -14
- package/dist/ColorPicker/ColorPickerProps.svelte +71 -0
- package/dist/ColorPicker/ColorPickerProps.svelte.d.ts +10 -0
- package/dist/{FileAttach/FileAttach.svelte → FileAttach.svelte} +3 -11
- package/dist/{FileAttach/FileAttach.svelte.d.ts → FileAttach.svelte.d.ts} +1 -1
- package/dist/Graph/Graph.svelte +3 -3
- package/dist/Graph/GraphProps.svelte +41 -0
- package/dist/Graph/GraphProps.svelte.d.ts +10 -0
- package/dist/Input/Input.svelte +42 -48
- package/dist/Input/InputProps.svelte +205 -0
- package/dist/Input/InputProps.svelte.d.ts +10 -0
- package/dist/Modal.svelte +54 -0
- package/dist/Modal.svelte.d.ts +12 -0
- package/dist/ProgressBar/ProgressBar.svelte +23 -21
- package/dist/ProgressBar/ProgressBarProps.svelte +114 -0
- package/dist/ProgressBar/ProgressBarProps.svelte.d.ts +10 -0
- package/dist/Select/Select.svelte +38 -23
- package/dist/Select/SelectProps.svelte +216 -0
- package/dist/Select/SelectProps.svelte.d.ts +10 -0
- package/dist/Slider/Slider.svelte +17 -10
- package/dist/Slider/SliderProps.svelte +113 -0
- package/dist/Slider/SliderProps.svelte.d.ts +10 -0
- package/dist/Switch/Switch.svelte +15 -10
- package/dist/Switch/SwitchProps.svelte +99 -0
- package/dist/Switch/SwitchProps.svelte.d.ts +10 -0
- package/dist/Table/Table.svelte +62 -38
- package/dist/Table/Table.svelte.d.ts +1 -1
- package/dist/Table/TableProps.svelte +233 -0
- package/dist/Table/TableProps.svelte.d.ts +10 -0
- package/dist/TextField/TextField.svelte +15 -9
- package/dist/TextField/TextFieldProps.svelte +44 -44
- package/dist/TextField/TextFieldProps.svelte.d.ts +1 -1
- package/dist/index.d.ts +12 -3
- package/dist/index.js +12 -3
- package/dist/libIcons/ButtonAdd.svelte +5 -2
- package/dist/libIcons/ButtonDelete.svelte +1 -1
- package/dist/libIcons/CrossIcon.svelte +9 -0
- package/dist/libIcons/CrossIcon.svelte.d.ts +18 -0
- package/dist/locales/translations.js +81 -6
- package/dist/options.d.ts +7 -12
- package/dist/options.js +44 -33
- package/dist/types.d.ts +50 -89
- package/dist/types.js +13 -1
- package/package.json +7 -3
- package/dist/Loader.svelte +0 -12
- package/dist/Loader.svelte.d.ts +0 -5
- package/dist/MessageModal.svelte +0 -54
- package/dist/MessageModal.svelte.d.ts +0 -10
|
@@ -1,68 +1,79 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { slide } from 'svelte/transition'
|
|
3
3
|
import type { IAccordionProps } from '../types'
|
|
4
|
+
import { twMerge } from 'tailwind-merge'
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
let {
|
|
7
|
+
id = crypto.randomUUID(),
|
|
8
|
+
isOpen = false,
|
|
9
|
+
outline = false,
|
|
10
|
+
wrapperClass = '',
|
|
11
|
+
size = { width: 1, height: 1 },
|
|
12
|
+
label = { name: '', class: 'text-left', icon: null },
|
|
13
|
+
children,
|
|
14
|
+
image,
|
|
15
|
+
}: IAccordionProps = $props()
|
|
7
16
|
|
|
8
17
|
const toggle = () => (isOpen = !isOpen)
|
|
9
18
|
</script>
|
|
10
19
|
|
|
11
20
|
<div
|
|
12
|
-
|
|
13
|
-
class=
|
|
14
|
-
? 'border-none'
|
|
15
|
-
|
|
16
|
-
|
|
21
|
+
{id}
|
|
22
|
+
class={twMerge(
|
|
23
|
+
`${outline ? 'border-none' : 'rounded-xl hover:shadow-md'} w-full
|
|
24
|
+
border border-[var(--border-color)] bg-[var(--container-color)] p-0 transition-shadow duration-250`,
|
|
25
|
+
wrapperClass,
|
|
26
|
+
)}
|
|
17
27
|
transition:slide={{ duration: 250 }}
|
|
18
28
|
>
|
|
19
29
|
<button
|
|
20
|
-
class="flex
|
|
21
|
-
{
|
|
30
|
+
class="flex w-full cursor-pointer items-center justify-between p-4 transition-shadow duration-250
|
|
31
|
+
{outline ? 'border-b border-[var(--border-color)]' : ''}"
|
|
22
32
|
onclick={toggle}
|
|
23
33
|
>
|
|
24
|
-
<div class="flex items-center
|
|
25
|
-
<span
|
|
26
|
-
{
|
|
27
|
-
|
|
28
|
-
{
|
|
29
|
-
{@const IconComponent =
|
|
34
|
+
<div class="flex w-full items-center">
|
|
35
|
+
<span
|
|
36
|
+
class={`flex h-8 w-8 shrink-0 items-center justify-center overflow-visible [&_svg]:h-full [&_svg]:max-h-full [&_svg]:w-full [&_svg]:max-w-full`}
|
|
37
|
+
>
|
|
38
|
+
{#if label?.icon}
|
|
39
|
+
{@const IconComponent = label?.icon}
|
|
30
40
|
<IconComponent />
|
|
31
41
|
{/if}
|
|
32
42
|
</span>
|
|
33
|
-
<
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
>
|
|
37
|
-
{props.label?.name}
|
|
38
|
-
</h4>
|
|
43
|
+
<span class="{twMerge('m-0 w-full cursor-pointer text-left font-semibold', label.class)} text-lg">
|
|
44
|
+
{label?.name}
|
|
45
|
+
</span>
|
|
39
46
|
</div>
|
|
40
47
|
|
|
41
|
-
<
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
48
|
+
<div class="w-10 pl-4">
|
|
49
|
+
<svg
|
|
50
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
51
|
+
class="h-[1.1rem] w-[1.1rem] transition-transform duration-250"
|
|
52
|
+
style="transform: rotate({isOpen ? 180 : 0}deg)"
|
|
53
|
+
viewBox="0 0 24 24"
|
|
54
|
+
>
|
|
55
|
+
<path
|
|
56
|
+
fill="none"
|
|
57
|
+
stroke="currentColor"
|
|
58
|
+
stroke-linecap="round"
|
|
59
|
+
stroke-linejoin="round"
|
|
60
|
+
stroke-width="2"
|
|
61
|
+
d="M18 12.5s-4.419 6-6 6s-6-6-6-6m12-7s-4.419 6-6 6s-6-6-6-6"
|
|
62
|
+
color="currentColor"
|
|
63
|
+
/>
|
|
64
|
+
</svg>
|
|
65
|
+
</div>
|
|
57
66
|
</button>
|
|
58
67
|
|
|
59
68
|
{#if isOpen}
|
|
60
69
|
<div
|
|
61
|
-
class="
|
|
70
|
+
class="grid w-full p-4 sm:p-3 {image ? 'gap-x-2' : 'gap-2'} {outline ? '' : 'border-t border-[var(--border-color)]'}"
|
|
62
71
|
transition:slide={{ duration: 250 }}
|
|
63
|
-
style=
|
|
72
|
+
style="grid-template-columns: repeat({size.width || 10}, minmax(0, 1fr));
|
|
73
|
+
grid-template-rows: repeat({size.height || 2}, {image ? 'minmax(6rem, auto)' : 'auto'});
|
|
74
|
+
{image ? `background-image: url(${image}); background-size: cover; background-position: center;` : ''}"
|
|
64
75
|
>
|
|
65
|
-
{@render
|
|
76
|
+
{@render children?.()}
|
|
66
77
|
</div>
|
|
67
78
|
{/if}
|
|
68
79
|
</div>
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
<!-- $lib/ElementsUI/AccordionProps.svelte -->
|
|
2
|
+
<script lang="ts">
|
|
3
|
+
import { t } from '../locales/i18n'
|
|
4
|
+
import { updateProperty, type IAccordionProps, type UIComponent } from '../types'
|
|
5
|
+
import * as UI from '..'
|
|
6
|
+
import { optionsStore } from '../options'
|
|
7
|
+
|
|
8
|
+
const { component, onPropertyChange } = $props<{
|
|
9
|
+
component: UIComponent & { properties: Partial<IAccordionProps> }
|
|
10
|
+
onPropertyChange: (value: string | object) => void
|
|
11
|
+
}>()
|
|
12
|
+
|
|
13
|
+
const initialType = $derived($optionsStore.ACCORDION_TYPE_OPTIONS.find((t) => t.value === component.properties.outline))
|
|
14
|
+
|
|
15
|
+
const initialAlign = $derived(
|
|
16
|
+
$optionsStore.ALIGN_OPTIONS.find((a) =>
|
|
17
|
+
(a.value as string).includes(component.properties.label?.class?.split(' ').find((cls: string) => cls.startsWith('text-'))),
|
|
18
|
+
),
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
const handleImageUpload = (event: Event) => {
|
|
22
|
+
const input = event.target as HTMLInputElement
|
|
23
|
+
if (!input.files || input.files.length === 0) return
|
|
24
|
+
|
|
25
|
+
const file = input.files[0]
|
|
26
|
+
const reader = new FileReader()
|
|
27
|
+
reader.onload = (e) => {
|
|
28
|
+
const base64String = e.target?.result as string
|
|
29
|
+
updateProperty('image', base64String, component, onPropertyChange)
|
|
30
|
+
}
|
|
31
|
+
reader.readAsDataURL(file)
|
|
32
|
+
}
|
|
33
|
+
</script>
|
|
34
|
+
|
|
35
|
+
{#if component && component.properties}
|
|
36
|
+
<div class="flex items-center justify-center gap-8">
|
|
37
|
+
<div class="flex w-1/3 flex-col items-center px-2">
|
|
38
|
+
<UI.Input
|
|
39
|
+
label={{ name: $t('constructor.props.label') }}
|
|
40
|
+
value={component.properties.label.name}
|
|
41
|
+
onUpdate={(value) => updateProperty('label.name', value as string, component, onPropertyChange)}
|
|
42
|
+
type="text"
|
|
43
|
+
/>
|
|
44
|
+
<UI.Select
|
|
45
|
+
label={{ name: $t('constructor.props.align') }}
|
|
46
|
+
type="buttons"
|
|
47
|
+
value={initialAlign}
|
|
48
|
+
options={$optionsStore.ALIGN_OPTIONS}
|
|
49
|
+
onUpdate={(option) => updateProperty('label.class', option.value as string, component, onPropertyChange)}
|
|
50
|
+
/>
|
|
51
|
+
</div>
|
|
52
|
+
<div class="flex w-1/3 flex-col items-center px-2">
|
|
53
|
+
<UI.Select
|
|
54
|
+
label={{ name: $t('constructor.props.type') }}
|
|
55
|
+
type="buttons"
|
|
56
|
+
value={initialType}
|
|
57
|
+
options={$optionsStore.ACCORDION_TYPE_OPTIONS}
|
|
58
|
+
onUpdate={(item) => updateProperty('outline', item.value as boolean, component, onPropertyChange)}
|
|
59
|
+
/>
|
|
60
|
+
</div>
|
|
61
|
+
<div class="flex w-1/3 flex-col items-center gap-2 px-2">
|
|
62
|
+
<UI.FileAttach
|
|
63
|
+
type="image"
|
|
64
|
+
label={{ name: $t('constructor.props.image') }}
|
|
65
|
+
accept="image/png, image/jpeg, image/webp"
|
|
66
|
+
bind:currentImage={component.properties.image}
|
|
67
|
+
onChange={handleImageUpload}
|
|
68
|
+
/>
|
|
69
|
+
<UI.Button
|
|
70
|
+
content={{ name: $t('constructor.props.removeimage') }}
|
|
71
|
+
wrapperClass="!w-auto"
|
|
72
|
+
onClick={() => updateProperty('image', '', component, onPropertyChange)}
|
|
73
|
+
/>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
{/if}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type IAccordionProps, type UIComponent } from '../types';
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
component: UIComponent & {
|
|
4
|
+
properties: Partial<IAccordionProps>;
|
|
5
|
+
};
|
|
6
|
+
onPropertyChange: (value: string | object) => void;
|
|
7
|
+
};
|
|
8
|
+
declare const AccordionProps: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
9
|
+
type AccordionProps = ReturnType<typeof AccordionProps>;
|
|
10
|
+
export default AccordionProps;
|
|
@@ -3,16 +3,18 @@
|
|
|
3
3
|
import { onMount } from 'svelte'
|
|
4
4
|
import type { IButtonProps } from '../types'
|
|
5
5
|
import { fly } from 'svelte/transition'
|
|
6
|
+
import { twMerge } from 'tailwind-merge'
|
|
6
7
|
|
|
7
8
|
let {
|
|
8
|
-
id =
|
|
9
|
-
wrapperClass = '
|
|
10
|
-
label = { name: '', class: '' },
|
|
11
|
-
name = '',
|
|
9
|
+
id = crypto.randomUUID(),
|
|
10
|
+
wrapperClass = '',
|
|
12
11
|
componentClass = '',
|
|
13
|
-
icon = { component: null, properties: {} },
|
|
14
|
-
info = '',
|
|
15
12
|
disabled = false,
|
|
13
|
+
content = {
|
|
14
|
+
name: '',
|
|
15
|
+
info: '',
|
|
16
|
+
icon: null,
|
|
17
|
+
},
|
|
16
18
|
keyBind,
|
|
17
19
|
onClick,
|
|
18
20
|
}: IButtonProps = $props()
|
|
@@ -43,49 +45,41 @@
|
|
|
43
45
|
|
|
44
46
|
/* Подписка на события клавиатуры */
|
|
45
47
|
onMount(() => {
|
|
46
|
-
if (keyBind)
|
|
47
|
-
window.addEventListener('keydown', handleKeyDown)
|
|
48
|
-
}
|
|
48
|
+
if (keyBind) window.addEventListener('keydown', handleKeyDown)
|
|
49
49
|
return () => {
|
|
50
|
-
if (keyBind)
|
|
51
|
-
window.removeEventListener('keydown', handleKeyDown)
|
|
52
|
-
}
|
|
50
|
+
if (keyBind) window.removeEventListener('keydown', handleKeyDown)
|
|
53
51
|
}
|
|
54
52
|
})
|
|
55
53
|
</script>
|
|
56
54
|
|
|
57
|
-
<div class={`relative flex w-full flex-col items-center
|
|
58
|
-
{#if label.name}
|
|
59
|
-
<h5 class={`w-full px-4 text-center ${label.class}`}>{label.name}</h5>
|
|
60
|
-
{/if}
|
|
61
|
-
|
|
55
|
+
<div class={twMerge(`bg-blue relative flex w-full flex-col items-center`, wrapperClass)}>
|
|
62
56
|
<div class="relative flex w-full grow items-center">
|
|
63
57
|
<button
|
|
64
|
-
|
|
65
|
-
class={
|
|
66
|
-
relative m-0 inline-block w-full items-center rounded-2xl border border-[var(--bg-color)]
|
|
58
|
+
{id}
|
|
59
|
+
class="{twMerge(
|
|
60
|
+
`relative m-0 inline-block w-full items-center rounded-2xl border border-[var(--bg-color)]
|
|
67
61
|
px-2 py-1 font-semibold shadow-sm transition duration-200 select-none
|
|
68
|
-
${disabled ? 'cursor-not-allowed opacity-50' : 'cursor-pointer hover:shadow-md active:scale-97'}
|
|
69
|
-
|
|
70
|
-
|
|
62
|
+
${disabled ? 'cursor-not-allowed opacity-50' : 'cursor-pointer hover:shadow-md active:scale-97'} `,
|
|
63
|
+
componentClass,
|
|
64
|
+
)} bg-[var(--bg-color)]"
|
|
71
65
|
onclick={handleClick}
|
|
72
66
|
{disabled}
|
|
73
|
-
aria-label={
|
|
67
|
+
aria-label={content.name}
|
|
74
68
|
onmouseenter={() => {
|
|
75
|
-
if (info) showInfo = true
|
|
69
|
+
if (content.info) showInfo = true
|
|
76
70
|
}}
|
|
77
71
|
onmouseleave={() => {
|
|
78
|
-
if (info) showInfo = false
|
|
72
|
+
if (content.info) showInfo = false
|
|
79
73
|
}}
|
|
80
74
|
>
|
|
81
75
|
<span class="flex flex-row items-center justify-center gap-2">
|
|
82
|
-
{#if icon
|
|
83
|
-
{@const IconComponent = icon
|
|
84
|
-
<IconComponent
|
|
76
|
+
{#if content.icon}
|
|
77
|
+
{@const IconComponent = content.icon}
|
|
78
|
+
<IconComponent />
|
|
85
79
|
{/if}
|
|
86
|
-
{#if name}
|
|
80
|
+
{#if content.name}
|
|
87
81
|
<div class="flex-1">
|
|
88
|
-
{name}
|
|
82
|
+
{content.name}
|
|
89
83
|
{#if keyBind}
|
|
90
84
|
<div class="text-xs opacity-70">
|
|
91
85
|
({keyBind.ctrlKey ? 'Ctrl+' : ''}{keyBind.shiftKey ? 'Shift+' : ''}{keyBind.altKey ? 'Alt+' : ''}{keyBind.key})
|
|
@@ -99,12 +93,12 @@
|
|
|
99
93
|
{#if showInfo}
|
|
100
94
|
<div
|
|
101
95
|
transition:fly={{ y: -15, duration: 300 }}
|
|
102
|
-
class="absolute bottom-full left-1/2 z-50 mb-2 w-max max-w-xs rounded-md bg-[var(--
|
|
96
|
+
class="absolute bottom-full left-1/2 z-50 mb-2 w-max max-w-xs rounded-md bg-[var(--container-color)] px-3 py-1 text-sm shadow-lg"
|
|
103
97
|
style="transform: translateX(-50%);"
|
|
104
98
|
>
|
|
105
|
-
{info}
|
|
99
|
+
{content.info}
|
|
106
100
|
<!-- Треугольная стрелка -->
|
|
107
|
-
<div class="absolute top-full left-1/2 h-2 w-2 -translate-x-1/2 -translate-y-1/2 rotate-45 transform bg-[var(--
|
|
101
|
+
<div class="absolute top-full left-1/2 h-2 w-2 -translate-x-1/2 -translate-y-1/2 rotate-45 transform bg-[var(--container-color)]"></div>
|
|
108
102
|
</div>
|
|
109
103
|
{/if}
|
|
110
104
|
</div>
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
<!-- $lib/ElementsUI/ButtonProps.svelte -->
|
|
2
|
+
<script lang="ts">
|
|
3
|
+
import { t } from '../locales/i18n'
|
|
4
|
+
import { type UIComponent, type IButtonProps, type ISelectOption, updateProperty } from '../types'
|
|
5
|
+
import * as UI from '..'
|
|
6
|
+
import { optionsStore } from '../options'
|
|
7
|
+
|
|
8
|
+
const { component, onPropertyChange } = $props<{
|
|
9
|
+
component: UIComponent & { properties: Partial<IButtonProps> }
|
|
10
|
+
onPropertyChange: (value: string | object) => void
|
|
11
|
+
}>()
|
|
12
|
+
|
|
13
|
+
let Header: ISelectOption = $derived(
|
|
14
|
+
$optionsStore.HEADER_OPTIONS.find((h) => h.value === component.properties.eventHandler.Header) ?? {
|
|
15
|
+
id: '',
|
|
16
|
+
name: '',
|
|
17
|
+
value: '',
|
|
18
|
+
class: '!w-1/4',
|
|
19
|
+
},
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
const initialColor = $derived(
|
|
23
|
+
$optionsStore.COLOR_OPTIONS.find((c) =>
|
|
24
|
+
(c.value as string).includes(component.properties.componentClass?.split(' ').find((cls: string) => cls.startsWith('bg-'))),
|
|
25
|
+
),
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
const initialHeight = $derived(
|
|
29
|
+
$optionsStore.HEIGHT_OPTIONS.find((h) =>
|
|
30
|
+
(h.value as string).includes(component.properties.componentClass?.split(' ').find((cls: string) => cls.startsWith('py-'))),
|
|
31
|
+
),
|
|
32
|
+
)
|
|
33
|
+
</script>
|
|
34
|
+
|
|
35
|
+
{#if component && component.properties}
|
|
36
|
+
<div class="relative flex flex-row items-start justify-center">
|
|
37
|
+
<!-- Сообщение для отправки в ws по нажатию кнопки -->
|
|
38
|
+
<div class="flex w-1/3 flex-col items-center px-2">
|
|
39
|
+
<UI.Select
|
|
40
|
+
wrapperClass="w-full"
|
|
41
|
+
label={{ name: $t('constructor.props.header') }}
|
|
42
|
+
type="buttons"
|
|
43
|
+
value={Header}
|
|
44
|
+
options={$optionsStore.HEADER_OPTIONS}
|
|
45
|
+
onUpdate={(option) => {
|
|
46
|
+
Header = option
|
|
47
|
+
updateProperty('eventHandler.Header', Header.value as string, component, onPropertyChange)
|
|
48
|
+
}}
|
|
49
|
+
/>
|
|
50
|
+
{#if Header.value === 'SET'}
|
|
51
|
+
<UI.Select
|
|
52
|
+
wrapperClass="w-full"
|
|
53
|
+
label={{ name: $t('constructor.props.argument') }}
|
|
54
|
+
type="buttons"
|
|
55
|
+
value={$optionsStore.FULL_ARGUMENT_OPTION.find((h) => h.value === component.properties.eventHandler.Argument)}
|
|
56
|
+
options={$optionsStore.FULL_ARGUMENT_OPTION}
|
|
57
|
+
onUpdate={(option) => {
|
|
58
|
+
updateProperty('eventHandler.Argument', option.value as string, component, onPropertyChange)
|
|
59
|
+
}}
|
|
60
|
+
/>
|
|
61
|
+
{/if}
|
|
62
|
+
{#if (component.properties.eventHandler.Argument !== 'Save' && component.properties.eventHandler.Argument !== 'NoSave') || Header.value !== 'SET'}
|
|
63
|
+
<UI.Input
|
|
64
|
+
wrapperClass={Header.value === 'SET' ? 'mt-1' : ''}
|
|
65
|
+
label={{ name: Header.value === 'SET' ? '' : $t('constructor.props.argument') }}
|
|
66
|
+
value={component.properties.eventHandler.Argument}
|
|
67
|
+
help={{ info: $t('constructor.props.argument.info'), autocomplete: 'on', regExp: /^[a-zA-Z0-9\-_]{0,32}$/ }}
|
|
68
|
+
maxlength={32}
|
|
69
|
+
onUpdate={(value) => updateProperty('eventHandler.Argument', value as string, component, onPropertyChange)}
|
|
70
|
+
/>
|
|
71
|
+
<UI.Input
|
|
72
|
+
label={{ name: $t('constructor.props.value') }}
|
|
73
|
+
value={component.properties.eventHandler.Value}
|
|
74
|
+
type="text"
|
|
75
|
+
maxlength={500}
|
|
76
|
+
onUpdate={(value) => updateProperty('eventHandler.Value', value as string, component, onPropertyChange)}
|
|
77
|
+
/>
|
|
78
|
+
{/if}
|
|
79
|
+
<UI.Input
|
|
80
|
+
label={{ name: $t('constructor.props.variables') }}
|
|
81
|
+
value={component.properties.eventHandler.Variables.join(' ')}
|
|
82
|
+
help={{ info: $t('constructor.props.variables.info'), autocomplete: 'on', regExp: /^[a-zA-Z0-9\-_ ":{}]{0,500}$/ }}
|
|
83
|
+
maxlength={500}
|
|
84
|
+
onUpdate={(value) => {
|
|
85
|
+
const parts = (value as string).trim().split(/\s+/)
|
|
86
|
+
updateProperty('eventHandler.Variables', parts, component, onPropertyChange)
|
|
87
|
+
}}
|
|
88
|
+
/>
|
|
89
|
+
</div>
|
|
90
|
+
<div class="flex w-1/3 flex-col px-2">
|
|
91
|
+
<UI.Input
|
|
92
|
+
label={{ name: $t('constructor.props.name') }}
|
|
93
|
+
value={component.properties.content.name}
|
|
94
|
+
onUpdate={(value) => updateProperty('content.name', value as string, component, onPropertyChange)}
|
|
95
|
+
/>
|
|
96
|
+
<UI.Select
|
|
97
|
+
label={{ name: $t('constructor.props.height') }}
|
|
98
|
+
type="buttons"
|
|
99
|
+
options={$optionsStore.HEIGHT_OPTIONS}
|
|
100
|
+
value={initialHeight}
|
|
101
|
+
onUpdate={(option) => updateProperty('componentClass', `${component.properties.componentClass} ${option.value}`, component, onPropertyChange)}
|
|
102
|
+
/>
|
|
103
|
+
<UI.Select
|
|
104
|
+
wrapperClass="h-14"
|
|
105
|
+
label={{ name: $t('constructor.props.colors') }}
|
|
106
|
+
type="buttons"
|
|
107
|
+
options={$optionsStore.COLOR_OPTIONS}
|
|
108
|
+
value={initialColor}
|
|
109
|
+
onUpdate={(option) => updateProperty('componentClass', `${component.properties.componentClass} ${option.value}`, component, onPropertyChange)}
|
|
110
|
+
/>
|
|
111
|
+
</div>
|
|
112
|
+
</div>
|
|
113
|
+
{/if}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type UIComponent, type IButtonProps } from '../types';
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
component: UIComponent & {
|
|
4
|
+
properties: Partial<IButtonProps>;
|
|
5
|
+
};
|
|
6
|
+
onPropertyChange: (value: string | object) => void;
|
|
7
|
+
};
|
|
8
|
+
declare const ButtonProps: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
9
|
+
type ButtonProps = ReturnType<typeof ButtonProps>;
|
|
10
|
+
export default ButtonProps;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
<!-- $lib/ElementsUI/ColorPicker.svelte -->
|
|
2
2
|
<script lang="ts">
|
|
3
|
+
import { twMerge } from 'tailwind-merge'
|
|
3
4
|
import type { IColorPickerProps } from '../types'
|
|
4
5
|
|
|
5
6
|
let {
|
|
6
|
-
id =
|
|
7
|
+
id = crypto.randomUUID(),
|
|
7
8
|
wrapperClass = '',
|
|
8
9
|
label = { name: '', class: '' },
|
|
9
10
|
value = [0, 0, 0],
|
|
@@ -108,14 +109,18 @@
|
|
|
108
109
|
window.addEventListener('mouseup', onUp)
|
|
109
110
|
}
|
|
110
111
|
|
|
111
|
-
const rgb = $derived(() =>
|
|
112
|
+
const rgb = $derived(() =>
|
|
113
|
+
mode === 'white' ? [whiteValue, whiteValue, whiteValue].map((v) => Math.round((v / 100) * 255)) : hsvToRgb(hsv.h, hsv.s, hsv.v),
|
|
114
|
+
)
|
|
112
115
|
const hex = $derived(() =>
|
|
113
116
|
rgb()
|
|
114
117
|
.map((v) => v.toString(16).padStart(2, '0'))
|
|
115
118
|
.join(' ')
|
|
116
119
|
.toUpperCase(),
|
|
117
120
|
)
|
|
118
|
-
const previewBaseColor = $derived(() =>
|
|
121
|
+
const previewBaseColor = $derived(() =>
|
|
122
|
+
mode === 'white' ? [255, 255, 255].map((c) => Math.round((whiteValue / 100) * c)) : hsvToRgb(hsv.h, hsv.s, 100),
|
|
123
|
+
)
|
|
119
124
|
|
|
120
125
|
const textColor = $derived(() => {
|
|
121
126
|
const [r, g, b] = rgb()
|
|
@@ -124,9 +129,9 @@
|
|
|
124
129
|
})
|
|
125
130
|
</script>
|
|
126
131
|
|
|
127
|
-
<div
|
|
132
|
+
<div {id} class={twMerge(`relative flex w-full flex-col items-center`, wrapperClass)}>
|
|
128
133
|
{#if label.name}
|
|
129
|
-
<h5 class={`mb-2 w-full px-4 text-center
|
|
134
|
+
<h5 class={twMerge(`mb-2 w-full px-4 text-center`, label.class)}>{label.name}</h5>
|
|
130
135
|
{/if}
|
|
131
136
|
|
|
132
137
|
<div class="flex w-full flex-row items-center gap-2">
|
|
@@ -134,7 +139,7 @@
|
|
|
134
139
|
<div class="flex w-full flex-col gap-2">
|
|
135
140
|
<!-- Выбор цвета -->
|
|
136
141
|
<div
|
|
137
|
-
class="hue-slider relative h-7 w-full cursor-pointer overflow-hidden rounded-full
|
|
142
|
+
class="hue-slider relative h-7 w-full cursor-pointer overflow-hidden rounded-full shadow-md"
|
|
138
143
|
role="slider"
|
|
139
144
|
aria-valuenow={null}
|
|
140
145
|
tabindex={null}
|
|
@@ -157,14 +162,17 @@
|
|
|
157
162
|
|
|
158
163
|
<!-- Яркость цвета -->
|
|
159
164
|
<div
|
|
160
|
-
class="brightness-slider relative h-4 w-full cursor-pointer overflow-hidden rounded-full
|
|
165
|
+
class="brightness-slider relative h-4 w-full cursor-pointer overflow-hidden rounded-full {mode === 'hsv' ? 'shadow-md' : ''}"
|
|
161
166
|
role="slider"
|
|
162
167
|
aria-valuenow={null}
|
|
163
168
|
tabindex={null}
|
|
164
169
|
onmousedown={(e) => handleDrag(e, 'brightness')}
|
|
165
170
|
>
|
|
166
171
|
{#if mode === 'hsv'}
|
|
167
|
-
<div
|
|
172
|
+
<div
|
|
173
|
+
class="absolute inset-0"
|
|
174
|
+
style={`background: linear-gradient(to right, rgb(0,0,0), rgb(${hsvToRgb(hsv.h, hsv.s, 100).join(',')}))`}
|
|
175
|
+
></div>
|
|
168
176
|
|
|
169
177
|
<div
|
|
170
178
|
class="pointer-events-none absolute top-1/2 h-7 w-1 -translate-x-1/2 -translate-y-1/2 rounded-full border-2 border-white"
|
|
@@ -175,7 +183,7 @@
|
|
|
175
183
|
|
|
176
184
|
<!-- Яркость белого цвета -->
|
|
177
185
|
<div
|
|
178
|
-
class="white-slider mt-4
|
|
186
|
+
class="white-slider relative mt-4 h-4 w-full cursor-pointer overflow-hidden rounded-full shadow-sm"
|
|
179
187
|
role="slider"
|
|
180
188
|
aria-valuenow={null}
|
|
181
189
|
tabindex={null}
|
|
@@ -192,14 +200,19 @@
|
|
|
192
200
|
</div>
|
|
193
201
|
|
|
194
202
|
<!-- Превью цвета -->
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
203
|
+
|
|
204
|
+
<div class="flex w-24 flex-col items-center">
|
|
205
|
+
<div
|
|
206
|
+
class={`flex size-15 flex-col justify-center gap-1 rounded-full px-2 font-mono text-sm shadow-md select-none ${textColor()}`}
|
|
207
|
+
style={`background: rgb(${previewBaseColor().join(',')})`}
|
|
208
|
+
></div>
|
|
209
|
+
<div class="w-full text-center font-semibold">{hex()}</div>
|
|
210
|
+
</div>
|
|
211
|
+
<!-- <div>
|
|
199
212
|
<div class="flex flex-col items-center">
|
|
200
213
|
<span class="w-full flex-shrink-0">{mode === 'white' ? 'White' : 'RGB'}</span>
|
|
201
214
|
<div class="пфз-1 w-full text-center tracking-wide">{hex()}</div>
|
|
202
215
|
</div>
|
|
203
|
-
</div>
|
|
216
|
+
</div> -->
|
|
204
217
|
</div>
|
|
205
218
|
</div>
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
<!-- $lib/ElementsUI/ButtonProps.svelte -->
|
|
2
|
+
<script lang="ts">
|
|
3
|
+
import { t } from '../locales/i18n'
|
|
4
|
+
import { type UIComponent, type IColorPickerProps, updateProperty } from '../types'
|
|
5
|
+
import * as UI from '..'
|
|
6
|
+
import { getContext } from 'svelte'
|
|
7
|
+
import { optionsStore } from '../options'
|
|
8
|
+
|
|
9
|
+
const { component, onPropertyChange } = $props<{
|
|
10
|
+
component: UIComponent & { properties: Partial<IColorPickerProps> }
|
|
11
|
+
onPropertyChange: (value: string | object) => void
|
|
12
|
+
}>()
|
|
13
|
+
|
|
14
|
+
const DeviceVariables = getContext<{ value: string; name: string }[]>('DeviceVariables')
|
|
15
|
+
let VARIABLE_OPTIONS = $derived(
|
|
16
|
+
DeviceVariables && Array.isArray(DeviceVariables)
|
|
17
|
+
? DeviceVariables.map((variable) => ({
|
|
18
|
+
id: variable.name,
|
|
19
|
+
value: variable.value,
|
|
20
|
+
name: `${variable.value} | ${variable.name}`,
|
|
21
|
+
}))
|
|
22
|
+
: [],
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
const initialAlign = $derived(
|
|
26
|
+
$optionsStore.ALIGN_OPTIONS.find((a) =>
|
|
27
|
+
(a.value as string).includes(component.properties.label?.class?.split(' ').find((cls: string) => cls.startsWith('text-'))),
|
|
28
|
+
),
|
|
29
|
+
)
|
|
30
|
+
</script>
|
|
31
|
+
|
|
32
|
+
{#if component && component.properties}
|
|
33
|
+
<div class="relative flex flex-row items-start justify-center">
|
|
34
|
+
<!-- Сообщение для отправки в ws по нажатию кнопки -->
|
|
35
|
+
<div class="flex w-1/3 flex-col items-center px-2">
|
|
36
|
+
<UI.Select
|
|
37
|
+
label={{ name: $t('constructor.props.variable') }}
|
|
38
|
+
options={VARIABLE_OPTIONS}
|
|
39
|
+
value={VARIABLE_OPTIONS.find((opt) => opt.value === component.properties.id.value)}
|
|
40
|
+
onUpdate={(value) => {
|
|
41
|
+
updateProperty('id', value.value as string, component, onPropertyChange)
|
|
42
|
+
updateProperty('eventHandler.Variables', value.value as string, component, onPropertyChange)
|
|
43
|
+
}}
|
|
44
|
+
/>
|
|
45
|
+
<UI.Select
|
|
46
|
+
label={{ name: $t('constructor.props.action') }}
|
|
47
|
+
type="buttons"
|
|
48
|
+
value={$optionsStore.SHORT_ARGUMENT_OPTION.find((h) => h.value === component.properties.eventHandler.Argument)}
|
|
49
|
+
options={$optionsStore.SHORT_ARGUMENT_OPTION}
|
|
50
|
+
onUpdate={(option) => {
|
|
51
|
+
updateProperty('eventHandler.Argument', option.value as string, component, onPropertyChange)
|
|
52
|
+
}}
|
|
53
|
+
/>
|
|
54
|
+
</div>
|
|
55
|
+
<div class="flex w-1/3 flex-col px-2">
|
|
56
|
+
<UI.Input
|
|
57
|
+
label={{ name: $t('constructor.props.label') }}
|
|
58
|
+
value={component.properties.label.name}
|
|
59
|
+
type="text"
|
|
60
|
+
onUpdate={(value) => updateProperty('label.name', value as string, component, onPropertyChange)}
|
|
61
|
+
/>
|
|
62
|
+
<UI.Select
|
|
63
|
+
label={{ name: $t('constructor.props.align') }}
|
|
64
|
+
type="buttons"
|
|
65
|
+
value={initialAlign}
|
|
66
|
+
options={$optionsStore.ALIGN_OPTIONS}
|
|
67
|
+
onUpdate={(option) => updateProperty('label.class', option.value as string, component, onPropertyChange)}
|
|
68
|
+
/>
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
{/if}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type UIComponent, type IColorPickerProps } from '../types';
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
component: UIComponent & {
|
|
4
|
+
properties: Partial<IColorPickerProps>;
|
|
5
|
+
};
|
|
6
|
+
onPropertyChange: (value: string | object) => void;
|
|
7
|
+
};
|
|
8
|
+
declare const ColorPickerProps: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
9
|
+
type ColorPickerProps = ReturnType<typeof ColorPickerProps>;
|
|
10
|
+
export default ColorPickerProps;
|
|
@@ -20,18 +20,12 @@
|
|
|
20
20
|
accept = '*/*',
|
|
21
21
|
imageSize = { height: '10rem', width: '10rem', fitMode: 'cover', form: 'square' },
|
|
22
22
|
disabled = false,
|
|
23
|
-
currentImage = null,
|
|
23
|
+
currentImage = $bindable(null),
|
|
24
24
|
onChange = () => {},
|
|
25
25
|
}: FileInputProps = $props()
|
|
26
26
|
|
|
27
27
|
let selectedFile = $state<File | null>(null)
|
|
28
|
-
let previewUrl = $
|
|
29
|
-
|
|
30
|
-
$effect(() => {
|
|
31
|
-
if (currentImage && !selectedFile) {
|
|
32
|
-
previewUrl = currentImage.startsWith('data:') ? currentImage : `data:image/png;base64,${currentImage}`
|
|
33
|
-
}
|
|
34
|
-
})
|
|
28
|
+
let previewUrl = $derived(currentImage ? (currentImage.startsWith('data:') ? currentImage : `data:image/png;base64,${currentImage}`) : null)
|
|
35
29
|
|
|
36
30
|
const handleFileChange = (event: Event) => {
|
|
37
31
|
const input = event.target as HTMLInputElement
|
|
@@ -43,9 +37,7 @@
|
|
|
43
37
|
const file = input.files[0]
|
|
44
38
|
selectedFile = file
|
|
45
39
|
|
|
46
|
-
if (file.type.startsWith('image/'))
|
|
47
|
-
previewUrl = URL.createObjectURL(file)
|
|
48
|
-
}
|
|
40
|
+
if (file.type.startsWith('image/')) previewUrl = URL.createObjectURL(file)
|
|
49
41
|
|
|
50
42
|
onChange(event, file)
|
|
51
43
|
}
|