poe-svelte-ui-lib 1.0.6 → 1.0.7

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.
Files changed (54) hide show
  1. package/dist/Accordion/Accordion.svelte +51 -40
  2. package/dist/Accordion/AccordionProps.svelte +76 -0
  3. package/dist/Accordion/AccordionProps.svelte.d.ts +10 -0
  4. package/dist/Button/Button.svelte +28 -34
  5. package/dist/Button/ButtonProps.svelte +113 -0
  6. package/dist/Button/ButtonProps.svelte.d.ts +10 -0
  7. package/dist/ColorPicker/ColorPicker.svelte +27 -14
  8. package/dist/ColorPicker/ColorPickerProps.svelte +71 -0
  9. package/dist/ColorPicker/ColorPickerProps.svelte.d.ts +10 -0
  10. package/dist/{FileAttach/FileAttach.svelte → FileAttach.svelte} +3 -11
  11. package/dist/{FileAttach/FileAttach.svelte.d.ts → FileAttach.svelte.d.ts} +1 -1
  12. package/dist/Graph/Graph.svelte +3 -3
  13. package/dist/Graph/GraphProps.svelte +41 -0
  14. package/dist/Graph/GraphProps.svelte.d.ts +10 -0
  15. package/dist/Input/Input.svelte +42 -48
  16. package/dist/Input/InputProps.svelte +205 -0
  17. package/dist/Input/InputProps.svelte.d.ts +10 -0
  18. package/dist/Modal.svelte +54 -0
  19. package/dist/Modal.svelte.d.ts +12 -0
  20. package/dist/ProgressBar/ProgressBar.svelte +23 -21
  21. package/dist/ProgressBar/ProgressBarProps.svelte +114 -0
  22. package/dist/ProgressBar/ProgressBarProps.svelte.d.ts +10 -0
  23. package/dist/Select/Select.svelte +38 -23
  24. package/dist/Select/SelectProps.svelte +216 -0
  25. package/dist/Select/SelectProps.svelte.d.ts +10 -0
  26. package/dist/Slider/Slider.svelte +17 -10
  27. package/dist/Slider/SliderProps.svelte +113 -0
  28. package/dist/Slider/SliderProps.svelte.d.ts +10 -0
  29. package/dist/Switch/Switch.svelte +15 -10
  30. package/dist/Switch/SwitchProps.svelte +99 -0
  31. package/dist/Switch/SwitchProps.svelte.d.ts +10 -0
  32. package/dist/Table/Table.svelte +62 -38
  33. package/dist/Table/Table.svelte.d.ts +1 -1
  34. package/dist/Table/TableProps.svelte +233 -0
  35. package/dist/Table/TableProps.svelte.d.ts +10 -0
  36. package/dist/TextField/TextField.svelte +15 -9
  37. package/dist/TextField/TextFieldProps.svelte +44 -44
  38. package/dist/TextField/TextFieldProps.svelte.d.ts +1 -1
  39. package/dist/index.d.ts +2 -3
  40. package/dist/index.js +2 -3
  41. package/dist/libIcons/ButtonAdd.svelte +5 -2
  42. package/dist/libIcons/ButtonDelete.svelte +1 -1
  43. package/dist/libIcons/CrossIcon.svelte +9 -0
  44. package/dist/libIcons/CrossIcon.svelte.d.ts +18 -0
  45. package/dist/locales/translations.js +81 -6
  46. package/dist/options.d.ts +7 -12
  47. package/dist/options.js +44 -33
  48. package/dist/types.d.ts +50 -89
  49. package/dist/types.js +13 -1
  50. package/package.json +7 -3
  51. package/dist/Loader.svelte +0 -12
  52. package/dist/Loader.svelte.d.ts +0 -5
  53. package/dist/MessageModal.svelte +0 -54
  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
- const props: IAccordionProps = $props()
6
- let isOpen = $state(props.isOpen)
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
- id={props.id?.value}
13
- class="border-[var(--border-color)] p-0 transition-shadow duration-250 {props.type === 'sub'
14
- ? 'border-none'
15
- : 'rounded-xl border bg-[var(--conteiner-color)] hover:shadow-md'}
16
- {props.componentClass}"
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 p-4 w-full cursor-pointer items-center justify-between transition-shadow duration-250
21
- {props.type === 'sub' ? 'border-b border-[var(--border-color)]' : ''}"
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 w-full">
25
- <span class={`flex items-center justify-center w-8 h-8 shrink-0 overflow-visible [&_svg]:w-full [&_svg]:h-full [&_svg]:max-w-full [&_svg]:max-h-full`}>
26
- {#if props.icon?.svg}
27
- {@html props.icon.svg}
28
- {:else if props.icon?.component}
29
- {@const IconComponent = props.icon?.component}
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
- <h4
34
- class="{props.label?.class}
35
- {props.label?.align === 'center' ? 'text-center flex-1' : props.label?.align === 'right' ? 'text-right flex-1 mr-2' : 'text-left flex-1 ml-2'}"
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
- <svg
42
- xmlns="http://www.w3.org/2000/svg"
43
- class="h-[1.1rem] w-[1.1rem] transition-transform duration-250"
44
- style="transform: rotate({isOpen ? 180 : 0}deg)"
45
- viewBox="0 0 24 24"
46
- >
47
- <path
48
- fill="none"
49
- stroke="currentColor"
50
- stroke-linecap="round"
51
- stroke-linejoin="round"
52
- stroke-width="2"
53
- d="M18 12.5s-4.419 6-6 6s-6-6-6-6m12-7s-4.419 6-6 6s-6-6-6-6"
54
- color="currentColor"
55
- />
56
- </svg>
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="flex w-full flex-wrap items-start justify-around p-2 {props.type === 'sub' ? '' : 'border-t border-[var(--border-color)]'}"
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={props.image ? `background-image: url('${props.image}'); background-size: cover;` : ''}
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 props.children?.()}
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 = { value: crypto.randomUUID(), name: '' },
9
- wrapperClass = 'bg-blue',
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 ${wrapperClass}`}>
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
- id={id.value}
65
- class={`
66
- relative m-0 inline-block w-full items-center rounded-2xl border border-[var(--bg-color)] bg-[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
- ${componentClass}
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={name || label.name}
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?.component}
83
- {@const IconComponent = icon?.component}
84
- <IconComponent {...icon?.properties} />
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(--conteiner-color)] px-3 py-1 text-sm shadow-lg"
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(--conteiner-color)]"></div>
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 = { name: '', value: crypto.randomUUID() },
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(() => (mode === 'white' ? [whiteValue, whiteValue, whiteValue].map((v) => Math.round((v / 100) * 255)) : hsvToRgb(hsv.h, hsv.s, hsv.v)))
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(() => (mode === 'white' ? [255, 255, 255].map((c) => Math.round((whiteValue / 100) * c)) : hsvToRgb(hsv.h, hsv.s, 100)))
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 id={id.value} class="relative flex w-full flex-col items-center {wrapperClass}">
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 ${label.class}`}>{label.name}</h5>
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 border border-gray-400"
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 border border-gray-400"
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 class="absolute inset-0" style={`background: linear-gradient(to right, rgb(0,0,0), rgb(${hsvToRgb(hsv.h, hsv.s, 100).join(',')}))`}></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 relative h-4 w-full cursor-pointer overflow-hidden rounded-full border border-gray-400"
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
- <div
196
- class={`flex h-26 w-28 flex-col justify-center gap-1 rounded-2xl border border-gray-400 px-2 font-mono text-sm select-none ${textColor()}`}
197
- style={`background: rgb(${previewBaseColor().join(',')})`}
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 = $state<string | null>(null)
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
  }