poe-svelte-ui-lib 1.0.1 → 1.0.4

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 (61) hide show
  1. package/LICENSE +3 -3
  2. package/README.md +1 -0
  3. package/dist/Accordion/Accordion.svelte +53 -53
  4. package/dist/Button/Button.svelte +111 -144
  5. package/dist/Button/Button.svelte.d.ts +1 -34
  6. package/dist/ColorPicker/ColorPicker.svelte +205 -207
  7. package/dist/FileAttach/FileAttach.svelte +103 -103
  8. package/dist/Graph/Graph.svelte +270 -270
  9. package/dist/Input/Input.svelte +240 -239
  10. package/dist/Loader.svelte +12 -12
  11. package/dist/MessageModal.svelte +54 -54
  12. package/dist/ProgressBar/ProgressBar.svelte +48 -48
  13. package/dist/Select/Select.svelte +189 -191
  14. package/dist/Slider/Slider.svelte +260 -260
  15. package/dist/Switch/Switch.svelte +84 -83
  16. package/dist/Table/Table.svelte +275 -276
  17. package/dist/TextField/TextField.svelte +22 -22
  18. package/dist/index.d.ts +0 -11
  19. package/dist/index.js +0 -11
  20. package/dist/{appIcons → libIcons}/ButtonAdd.svelte +10 -10
  21. package/dist/{appIcons → libIcons}/ButtonDelete.svelte +13 -13
  22. package/dist/{appIcons → libIcons}/LoaderRotate.svelte +9 -9
  23. package/dist/options.d.ts +11 -11
  24. package/dist/options.js +27 -27
  25. package/dist/types.d.ts +1 -1
  26. package/package.json +48 -47
  27. package/dist/Accordion/AccordionProps.svelte +0 -70
  28. package/dist/Accordion/AccordionProps.svelte.d.ts +0 -10
  29. package/dist/Button/ButtonProps.svelte +0 -200
  30. package/dist/Button/ButtonProps.svelte.d.ts +0 -10
  31. package/dist/ColorPicker/ColorPickerProps.svelte +0 -100
  32. package/dist/ColorPicker/ColorPickerProps.svelte.d.ts +0 -10
  33. package/dist/Graph/GraphProps.svelte +0 -56
  34. package/dist/Graph/GraphProps.svelte.d.ts +0 -10
  35. package/dist/Input/InputProps.svelte +0 -221
  36. package/dist/Input/InputProps.svelte.d.ts +0 -10
  37. package/dist/ProgressBar/ProgressBarProps.svelte +0 -145
  38. package/dist/ProgressBar/ProgressBarProps.svelte.d.ts +0 -10
  39. package/dist/Select/SelectProps.svelte +0 -260
  40. package/dist/Select/SelectProps.svelte.d.ts +0 -10
  41. package/dist/Slider/SliderProps.svelte +0 -161
  42. package/dist/Slider/SliderProps.svelte.d.ts +0 -10
  43. package/dist/Switch/SwitchProps.svelte +0 -144
  44. package/dist/Switch/SwitchProps.svelte.d.ts +0 -10
  45. package/dist/Table/TableProps.svelte +0 -286
  46. package/dist/Table/TableProps.svelte.d.ts +0 -10
  47. package/dist/TextField/TextFieldProps.svelte +0 -92
  48. package/dist/TextField/TextFieldProps.svelte.d.ts +0 -10
  49. package/dist/locales/CircleFlagsEn.svelte +0 -14
  50. package/dist/locales/CircleFlagsEn.svelte.d.ts +0 -26
  51. package/dist/locales/CircleFlagsRu.svelte +0 -8
  52. package/dist/locales/CircleFlagsRu.svelte.d.ts +0 -26
  53. package/dist/locales/CircleFlagsZh.svelte +0 -8
  54. package/dist/locales/CircleFlagsZh.svelte.d.ts +0 -26
  55. package/dist/locales/i18n.d.ts +0 -10
  56. package/dist/locales/i18n.js +0 -36
  57. package/dist/locales/translations.d.ts +0 -7
  58. package/dist/locales/translations.js +0 -450
  59. /package/dist/{appIcons → libIcons}/ButtonAdd.svelte.d.ts +0 -0
  60. /package/dist/{appIcons → libIcons}/ButtonDelete.svelte.d.ts +0 -0
  61. /package/dist/{appIcons → libIcons}/LoaderRotate.svelte.d.ts +0 -0
@@ -1,276 +1,275 @@
1
- <!-- $lib/ElementsUI/Table.svelte -->
2
- <script lang="ts">
3
- import { t } from '../locales/i18n'
4
- import { get } from 'svelte/store'
5
- import type { ITableHeader, ITableProps } from '../types'
6
- import { fly } from 'svelte/transition'
7
-
8
- let {
9
- id = { value: crypto.randomUUID(), name: '' },
10
- wrapperClass = 'bg-blue',
11
- label = { name: '', class: '' },
12
- tableBody = [],
13
- tableHeader = [],
14
- cursor = null,
15
- loader,
16
- getData = () => {},
17
- showInfo = true,
18
- modalData = $bindable({ isOpen: false, rawData: '', formattedData: '' }),
19
- onClick,
20
- }: ITableProps<any> = $props()
21
-
22
- /* Сортировка */
23
- let sortState: {
24
- key: string | null
25
- direction: 'asc' | 'desc' | null
26
- } = {
27
- key: null,
28
- direction: null,
29
- }
30
-
31
- /* Сортировка столбцов */
32
- const sortRows = (key: string) => {
33
- if (sortState.key === key) {
34
- sortState.direction = sortState.direction === 'asc' ? 'desc' : 'asc'
35
- } else {
36
- sortState.key = key
37
- sortState.direction = 'asc'
38
- }
39
-
40
- tableBody = [...tableBody].sort((a, b) => {
41
- const aValue = a[key]
42
- const bValue = b[key]
43
- if (typeof aValue === 'number' && typeof bValue === 'number') {
44
- return sortState.direction === 'asc' ? aValue - bValue : bValue - aValue
45
- }
46
- if (aValue instanceof Date && bValue instanceof Date) {
47
- return sortState.direction === 'asc' ? aValue.getTime() - bValue.getTime() : bValue.getTime() - aValue.getTime()
48
- }
49
- const strA = String(aValue).toLowerCase()
50
- const strB = String(bValue).toLowerCase()
51
- const numA = strA.match(/\d+/g)?.[0] || ''
52
- const numB = strB.match(/\d+/g)?.[0] || ''
53
- if (numA && numB) {
54
- const numCompare = parseInt(numA, 10) - parseInt(numB, 10)
55
- if (numCompare !== 0) {
56
- return sortState.direction === 'asc' ? numCompare : -numCompare
57
- }
58
- }
59
- const stringCompare = strA.localeCompare(strB)
60
- return sortState.direction === 'asc' ? stringCompare : -stringCompare
61
- })
62
- }
63
-
64
- /* Запрос данных, если в конце списка */
65
- let container: HTMLElement | null = $state(null)
66
- function handleScroll() {
67
- if (!container) return
68
- const { scrollTop, clientHeight, scrollHeight } = container
69
- if (scrollTop + clientHeight >= scrollHeight - 50 && cursor !== null && loader && !get(loader)) {
70
- getData()
71
- }
72
- }
73
-
74
- function buttonClick(row: any, button: any) {
75
- if (button.onClick) button.onClick(row)
76
- else if (button.eventHandler && onClick) {
77
- let value: Record<string, boolean | string | number | number[] | object | null> = {}
78
- button.eventHandler.Variables.forEach((v: string) => {
79
- value[v] = row[v]
80
- })
81
- button.eventHandler.Value = JSON.stringify(value)
82
- onClick(button.eventHandler)
83
- }
84
- }
85
-
86
- let copiedCell = $state({ x: '', y: -1 })
87
- let tooltip = $state({
88
- show: false,
89
- text: '',
90
- x: 0,
91
- y: 0,
92
- })
93
-
94
- const showModal = async (text: string, formatting?: (text: string) => string) => {
95
- modalData = {
96
- isOpen: !modalData.isOpen,
97
- rawData: text,
98
- formattedData: formatting ? formatting(text) : (text ?? ''),
99
- }
100
- }
101
-
102
- const showTooltip = (event: MouseEvent, text: string, formatting?: (text: string) => string) => {
103
- tooltip = {
104
- show: true,
105
- text: formatting ? formatting(text) : (text ?? ''),
106
- x: event.clientX,
107
- y: event.clientY,
108
- }
109
- }
110
-
111
- const hideTooltip = () => {
112
- tooltip.show = false
113
- }
114
-
115
- /* Для работы этой проверки в описании столбцов таблицы нужно явно указать что строка будет пустая при отсутствии иконки в БД -
116
- src: (row) => (row.icon ? `data:image/png;base64,${row.icon}` : '') */
117
- const hasImage = (column: ITableHeader<any>, row: any): boolean => {
118
- const src = typeof column.image?.src === 'function' ? column.image.src(row) : column.image?.src
119
- return !!src
120
- }
121
- </script>
122
-
123
- <div id={id.value} class={`flex h-full w-full flex-col overflow-hidden ${wrapperClass}`}>
124
- {#if label.name}
125
- <h5 class={`w-full px-4 text-center ${label.class}`}>{label.name}</h5>
126
- {/if}
127
-
128
- <div class="flex h-full flex-col overflow-hidden rounded-xl border-[var(--border-color)]">
129
- <!-- Table Header -->
130
- <div class="grid font-semibold" style={`grid-template-columns: ${tableHeader.map((c) => c.width || 'minmax(0, 1fr)').join(' ')};`}>
131
- {#each tableHeader as column (column)}
132
- <div class="justify-center bg-[var(--bg-color)] p-2 text-center">
133
- <div class="flex items-center justify-start gap-2">
134
- <span>{column.label}</span>
135
- {#if column.sortable}
136
- <button
137
- class="cursor-pointer font-bold transition-transform duration-75 hover:scale-110 active:scale-95"
138
- onclick={() => sortRows(column.key as string)}
139
- >
140
- ↑↓
141
- </button>
142
- {/if}
143
- </div>
144
- </div>
145
- {/each}
146
- </div>
147
-
148
- <!-- Table Body с прокруткой -->
149
- <div class="flex-1 overflow-y-auto bg-[var(--conteiner-color)]/50" bind:this={container} onscroll={handleScroll}>
150
- <div class="grid min-w-0" style={`grid-template-columns: ${tableHeader.map((c) => c.width || 'minmax(0, 1fr)').join(' ')};`}>
151
- {#each tableBody as row, index (row)}
152
- {#each tableHeader as column (column)}
153
- <div
154
- class="relative flex w-full min-w-0 items-center px-2 py-1 break-words
155
- {index % 2 ? '!bg-[var(--field-color)]' : ''}
156
- {column.cellClass}
157
- {column.align === 'center'
158
- ? 'flex justify-center text-center'
159
- : column.align === 'right'
160
- ? 'flex justify-end text-right'
161
- : 'flex justify-start text-left'}"
162
- >
163
- {#if column.buttons}
164
- <div class="flex w-full flex-col gap-1">
165
- {#each column.buttons as button (button)}
166
- <button
167
- class="
168
- cursor-pointer rounded-full !bg-[var(--bg-color)] px-4 py-1 font-medium
169
- transition-shadow outline-none select-none hover:shadow-md
170
- {typeof button.class === 'function' ? button.class(row) : button.class}
171
- "
172
- onclick={() => buttonClick(row, button)}
173
- >
174
- {typeof button.name === 'function' ? button.name(row) : button.name}
175
- </button>
176
- {/each}
177
- </div>
178
- {:else if column.image}
179
- <div class="flex items-center justify-center" style={`width: ${column.image.width || '5rem'}; height: ${column.image.height || '5rem'};`}>
180
- {#if hasImage(column, row)}
181
- <img
182
- src={typeof column.image?.src === 'function' ? column.image.src(row) : column.image?.src || ''}
183
- alt={column.image.alt ?? 'Image'}
184
- class="h-full w-full object-cover {column.image.class || ''}"
185
- loading="lazy"
186
- />
187
- {:else if column.image.defaultIcon}
188
- <column.image.defaultIcon />
189
- {/if}
190
- </div>
191
- {:else}
192
- <div
193
- class="w-full max-w-full break-words {column.overflow?.truncated ? 'overflow-hidden text-ellipsis whitespace-nowrap' : 'whitespace-normal'}"
194
- onmouseenter={column.overflow?.truncated ? (e) => showTooltip(e, row[column.key], column.overflow?.formatting) : undefined}
195
- onmouseleave={column.overflow?.truncated ? hideTooltip : undefined}
196
- onmousemove={column.overflow?.truncated
197
- ? (e) => {
198
- tooltip.x = e.clientX
199
- tooltip.y = e.clientY
200
- }
201
- : undefined}
202
- role="columnheader"
203
- tabindex={null}
204
- >
205
- {#if column.overflow?.modal}
206
- <button
207
- class="w-full cursor-pointer overflow-hidden text-left text-ellipsis whitespace-nowrap"
208
- onclick={(e) => {
209
- e.stopPropagation()
210
- showModal(row[column.key], column.overflow?.formatting)
211
- }}
212
- >
213
- {@html row[column.key]}
214
- </button>
215
- {:else}
216
- {@html row[column.key]}
217
- {/if}
218
- </div>
219
-
220
- {#if column.overflow?.copy}
221
- <button
222
- class="right-2 flex cursor-pointer border-none bg-transparent"
223
- onclick={(e) => {
224
- e.preventDefault()
225
- navigator.clipboard.writeText(row[column.key])
226
- copiedCell = { x: column.key as string, y: index }
227
- setTimeout(() => (copiedCell = { x: '', y: -1 }), 1000)
228
- }}
229
- aria-label="Копировать текст"
230
- >
231
- <svg xmlns="http://www.w3.org/2000/svg" width="1.3em" height="1.3em" viewBox="0 0 24 24">
232
- <g fill="none" stroke="currentColor" stroke-width="1.5">
233
- <path
234
- 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"
235
- />
236
- <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" />
237
- </g>
238
- </svg>
239
- </button>
240
-
241
- {#if copiedCell.y === index && copiedCell.x === column.key}
242
- <div
243
- class="absolute top-1/2 right-10 -translate-y-1/2 transform rounded-md bg-[var(--green-color)] px-2 py-1 text-sm shadow-lg"
244
- transition:fly={{ x: 10, duration: 200 }}
245
- >
246
- {$t('component.input.copy')}
247
- </div>
248
- {/if}
249
- {/if}
250
- {/if}
251
- </div>
252
- {/each}
253
- {/each}
254
- </div>
255
- </div>
256
-
257
- {#if tooltip.show}
258
- <div
259
- class="fixed z-50 max-w-xs rounded-md px-2 py-1 text-sm whitespace-pre-wrap shadow-lg"
260
- style="background: color-mix(in srgb, var(--yellow-color) 30%, var(--back-color)); transform: translateX(-50%); left: {tooltip.x +
261
- 10}px; top: {tooltip.y + 10}px;"
262
- transition:fly={{ y: 10, duration: 200 }}
263
- role="tooltip"
264
- >
265
- {@html tooltip.text}
266
- </div>
267
- {/if}
268
-
269
- <!-- Нижнее поле для сводной информации -->
270
- {#if showInfo}
271
- <div class="flex h-8 items-center justify-center bg-[var(--bg-color)]">
272
- <h5>{$t('catalog.nums')} {tableBody.length}</h5>
273
- </div>
274
- {/if}
275
- </div>
276
- </div>
1
+ <!-- $lib/ElementsUI/Table.svelte -->
2
+ <script lang="ts">
3
+ import { get } from 'svelte/store'
4
+ import type { ITableHeader, ITableProps } from '../types'
5
+ import { fly } from 'svelte/transition'
6
+
7
+ let {
8
+ id = { value: crypto.randomUUID(), name: '' },
9
+ wrapperClass = 'bg-blue',
10
+ label = { name: '', class: '' },
11
+ tableBody = [],
12
+ tableHeader = [],
13
+ cursor = null,
14
+ loader,
15
+ getData = () => {},
16
+ info = '',
17
+ modalData = $bindable({ isOpen: false, rawData: '', formattedData: '' }),
18
+ onClick,
19
+ }: ITableProps<any> = $props()
20
+
21
+ /* Сортировка */
22
+ let sortState: {
23
+ key: string | null
24
+ direction: 'asc' | 'desc' | null
25
+ } = {
26
+ key: null,
27
+ direction: null,
28
+ }
29
+
30
+ /* Сортировка столбцов */
31
+ const sortRows = (key: string) => {
32
+ if (sortState.key === key) {
33
+ sortState.direction = sortState.direction === 'asc' ? 'desc' : 'asc'
34
+ } else {
35
+ sortState.key = key
36
+ sortState.direction = 'asc'
37
+ }
38
+
39
+ tableBody = [...tableBody].sort((a, b) => {
40
+ const aValue = a[key]
41
+ const bValue = b[key]
42
+ if (typeof aValue === 'number' && typeof bValue === 'number') {
43
+ return sortState.direction === 'asc' ? aValue - bValue : bValue - aValue
44
+ }
45
+ if (aValue instanceof Date && bValue instanceof Date) {
46
+ return sortState.direction === 'asc' ? aValue.getTime() - bValue.getTime() : bValue.getTime() - aValue.getTime()
47
+ }
48
+ const strA = String(aValue).toLowerCase()
49
+ const strB = String(bValue).toLowerCase()
50
+ const numA = strA.match(/\d+/g)?.[0] || ''
51
+ const numB = strB.match(/\d+/g)?.[0] || ''
52
+ if (numA && numB) {
53
+ const numCompare = parseInt(numA, 10) - parseInt(numB, 10)
54
+ if (numCompare !== 0) {
55
+ return sortState.direction === 'asc' ? numCompare : -numCompare
56
+ }
57
+ }
58
+ const stringCompare = strA.localeCompare(strB)
59
+ return sortState.direction === 'asc' ? stringCompare : -stringCompare
60
+ })
61
+ }
62
+
63
+ /* Запрос данных, если в конце списка */
64
+ let container: HTMLElement | null = $state(null)
65
+ function handleScroll() {
66
+ if (!container) return
67
+ const { scrollTop, clientHeight, scrollHeight } = container
68
+ if (scrollTop + clientHeight >= scrollHeight - 50 && cursor !== null && loader && !get(loader)) {
69
+ getData()
70
+ }
71
+ }
72
+
73
+ function buttonClick(row: any, button: any) {
74
+ if (button.onClick) button.onClick(row)
75
+ else if (button.eventHandler && onClick) {
76
+ let value: Record<string, boolean | string | number | number[] | object | null> = {}
77
+ button.eventHandler.Variables.forEach((v: string) => {
78
+ value[v] = row[v]
79
+ })
80
+ button.eventHandler.Value = JSON.stringify(value)
81
+ onClick(button.eventHandler)
82
+ }
83
+ }
84
+
85
+ let copiedCell = $state({ x: '', y: -1 })
86
+ let tooltip = $state({
87
+ show: false,
88
+ text: '',
89
+ x: 0,
90
+ y: 0,
91
+ })
92
+
93
+ const showModal = async (text: string, formatting?: (text: string) => string) => {
94
+ modalData = {
95
+ isOpen: !modalData.isOpen,
96
+ rawData: text,
97
+ formattedData: formatting ? formatting(text) : (text ?? ''),
98
+ }
99
+ }
100
+
101
+ const showTooltip = (event: MouseEvent, text: string, formatting?: (text: string) => string) => {
102
+ tooltip = {
103
+ show: true,
104
+ text: formatting ? formatting(text) : (text ?? ''),
105
+ x: event.clientX,
106
+ y: event.clientY,
107
+ }
108
+ }
109
+
110
+ const hideTooltip = () => {
111
+ tooltip.show = false
112
+ }
113
+
114
+ /* Для работы этой проверки в описании столбцов таблицы нужно явно указать что строка будет пустая при отсутствии иконки в БД -
115
+ src: (row) => (row.icon ? `data:image/png;base64,${row.icon}` : '') */
116
+ const hasImage = (column: ITableHeader<any>, row: any): boolean => {
117
+ const src = typeof column.image?.src === 'function' ? column.image.src(row) : column.image?.src
118
+ return !!src
119
+ }
120
+ </script>
121
+
122
+ <div id={id.value} class={`flex h-full w-full flex-col overflow-hidden ${wrapperClass}`}>
123
+ {#if label.name}
124
+ <h5 class={`w-full px-4 text-center ${label.class}`}>{label.name}</h5>
125
+ {/if}
126
+
127
+ <div class="flex h-full flex-col overflow-hidden rounded-xl border-[var(--border-color)]">
128
+ <!-- Table Header -->
129
+ <div class="grid font-semibold" style={`grid-template-columns: ${tableHeader.map((c) => c.width || 'minmax(0, 1fr)').join(' ')};`}>
130
+ {#each tableHeader as column (column)}
131
+ <div class="justify-center bg-[var(--bg-color)] p-2 text-center">
132
+ <div class="flex items-center justify-start gap-2">
133
+ <span>{column.label}</span>
134
+ {#if column.sortable}
135
+ <button
136
+ class="cursor-pointer font-bold transition-transform duration-75 hover:scale-110 active:scale-95"
137
+ onclick={() => sortRows(column.key as string)}
138
+ >
139
+ ↑↓
140
+ </button>
141
+ {/if}
142
+ </div>
143
+ </div>
144
+ {/each}
145
+ </div>
146
+
147
+ <!-- Table Body с прокруткой -->
148
+ <div class="flex-1 overflow-y-auto bg-[var(--conteiner-color)]/50" bind:this={container} onscroll={handleScroll}>
149
+ <div class="grid min-w-0" style={`grid-template-columns: ${tableHeader.map((c) => c.width || 'minmax(0, 1fr)').join(' ')};`}>
150
+ {#each tableBody as row, index (row)}
151
+ {#each tableHeader as column (column)}
152
+ <div
153
+ class="relative flex w-full min-w-0 items-center px-2 py-1 break-words
154
+ {index % 2 ? '!bg-[var(--back-color)]/40' : ''}
155
+ {column.cellClass}
156
+ {column.align === 'center'
157
+ ? 'flex justify-center text-center'
158
+ : column.align === 'right'
159
+ ? 'flex justify-end text-right'
160
+ : 'flex justify-start text-left'}"
161
+ >
162
+ {#if column.buttons}
163
+ <div class="flex w-full flex-col gap-1">
164
+ {#each column.buttons as button (button)}
165
+ <button
166
+ class="
167
+ cursor-pointer rounded-full !bg-[var(--bg-color)] px-4 py-1 font-medium
168
+ transition-shadow outline-none select-none hover:shadow-md
169
+ {typeof button.class === 'function' ? button.class(row) : button.class}
170
+ "
171
+ onclick={() => buttonClick(row, button)}
172
+ >
173
+ {typeof button.name === 'function' ? button.name(row) : button.name}
174
+ </button>
175
+ {/each}
176
+ </div>
177
+ {:else if column.image}
178
+ <div class="flex items-center justify-center" style={`width: ${column.image.width || '5rem'}; height: ${column.image.height || '5rem'};`}>
179
+ {#if hasImage(column, row)}
180
+ <img
181
+ src={typeof column.image?.src === 'function' ? column.image.src(row) : column.image?.src || ''}
182
+ alt={column.image.alt ?? 'Image'}
183
+ class="h-full w-full object-cover {column.image.class || ''}"
184
+ loading="lazy"
185
+ />
186
+ {:else if column.image.defaultIcon}
187
+ <column.image.defaultIcon />
188
+ {/if}
189
+ </div>
190
+ {:else}
191
+ <div
192
+ class="w-full max-w-full break-words {column.overflow?.truncated ? 'overflow-hidden text-ellipsis whitespace-nowrap' : 'whitespace-normal'}"
193
+ onmouseenter={column.overflow?.truncated ? (e) => showTooltip(e, row[column.key], column.overflow?.formatting) : undefined}
194
+ onmouseleave={column.overflow?.truncated ? hideTooltip : undefined}
195
+ onmousemove={column.overflow?.truncated
196
+ ? (e) => {
197
+ tooltip.x = e.clientX
198
+ tooltip.y = e.clientY
199
+ }
200
+ : undefined}
201
+ role="columnheader"
202
+ tabindex={null}
203
+ >
204
+ {#if column.overflow?.modal}
205
+ <button
206
+ class="w-full cursor-pointer overflow-hidden text-left text-ellipsis whitespace-nowrap"
207
+ onclick={(e) => {
208
+ e.stopPropagation()
209
+ showModal(row[column.key], column.overflow?.formatting)
210
+ }}
211
+ >
212
+ {@html row[column.key]}
213
+ </button>
214
+ {:else}
215
+ {@html row[column.key]}
216
+ {/if}
217
+ </div>
218
+
219
+ {#if column.overflow?.copy}
220
+ <button
221
+ class="right-2 flex cursor-pointer border-none bg-transparent"
222
+ onclick={(e) => {
223
+ e.preventDefault()
224
+ navigator.clipboard.writeText(row[column.key])
225
+ copiedCell = { x: column.key as string, y: index }
226
+ setTimeout(() => (copiedCell = { x: '', y: -1 }), 1000)
227
+ }}
228
+ aria-label="Копировать текст"
229
+ >
230
+ <svg xmlns="http://www.w3.org/2000/svg" width="1.3em" height="1.3em" viewBox="0 0 24 24">
231
+ <g fill="none" stroke="currentColor" stroke-width="1.5">
232
+ <path
233
+ 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"
234
+ />
235
+ <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" />
236
+ </g>
237
+ </svg>
238
+ </button>
239
+
240
+ {#if copiedCell.y === index && copiedCell.x === column.key}
241
+ <div
242
+ class="absolute top-1/2 right-10 -translate-y-1/2 transform rounded-md bg-[var(--green-color)] px-2 py-1 text-sm shadow-lg"
243
+ transition:fly={{ x: 10, duration: 200 }}
244
+ >
245
+
246
+ </div>
247
+ {/if}
248
+ {/if}
249
+ {/if}
250
+ </div>
251
+ {/each}
252
+ {/each}
253
+ </div>
254
+ </div>
255
+
256
+ {#if tooltip.show}
257
+ <div
258
+ class="fixed z-50 max-w-xs rounded-md px-2 py-1 text-sm whitespace-pre-wrap shadow-lg"
259
+ style="background: color-mix(in srgb, var(--yellow-color) 30%, var(--back-color)); transform: translateX(-50%); left: {tooltip.x +
260
+ 10}px; top: {tooltip.y + 10}px;"
261
+ transition:fly={{ y: 10, duration: 200 }}
262
+ role="tooltip"
263
+ >
264
+ {@html tooltip.text}
265
+ </div>
266
+ {/if}
267
+
268
+ <!-- Нижнее поле для сводной информации -->
269
+ {#if info != ''}
270
+ <div class="flex h-8 items-center justify-center bg-[var(--bg-color)]">
271
+ <h5>{info}</h5>
272
+ </div>
273
+ {/if}
274
+ </div>
275
+ </div>
@@ -1,22 +1,22 @@
1
- <script lang="ts">
2
- import type { ITextFieldProps } from '../types'
3
-
4
- let {
5
- id = { value: crypto.randomUUID(), name: '' },
6
- wrapperClass = '',
7
- label = { name: '', class: '' },
8
- type = 'small',
9
- bold = false,
10
- italic = false,
11
- }: ITextFieldProps = $props()
12
-
13
- const textSize = {
14
- small: 'text-base',
15
- medium: 'text-xl',
16
- xlarge: 'text-2xl',
17
- }
18
- </script>
19
-
20
- <div id={id.value} class="relative flex w-full flex-col items-center {wrapperClass}">
21
- <p class="w-full text-center {label.class} {textSize[type]} {bold ? 'font-bold' : ''} {italic ? 'italic' : ''}">{label.name}</p>
22
- </div>
1
+ <script lang="ts">
2
+ import type { ITextFieldProps } from '../types'
3
+
4
+ let {
5
+ id = { value: crypto.randomUUID(), name: '' },
6
+ wrapperClass = '',
7
+ label = { name: '', class: '' },
8
+ type = 'small',
9
+ bold = false,
10
+ italic = false,
11
+ }: ITextFieldProps = $props()
12
+
13
+ const textSize = {
14
+ small: 'text-base',
15
+ medium: 'text-xl',
16
+ xlarge: 'text-2xl',
17
+ }
18
+ </script>
19
+
20
+ <div id={id.value} class="relative flex w-full flex-col items-center {wrapperClass}">
21
+ <p class="w-full text-center {label.class} {textSize[type]} {bold ? 'font-bold' : ''} {italic ? 'italic' : ''}">{label.name}</p>
22
+ </div>