poe-svelte-ui-lib 1.1.21 → 1.2.0

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 (68) hide show
  1. package/dist/Accordion/AccordionProps.svelte +3 -3
  2. package/dist/FileAttach/FileAttach.svelte +0 -1
  3. package/dist/Graph/GraphProps.svelte +0 -2
  4. package/dist/{Accordion/IconsLib → IconsCatalog}/common.edit.svg +5 -4
  5. package/dist/{Accordion/IconsLib → IconsCatalog}/iconsLib.js +2 -2
  6. package/dist/{Accordion/IconsLib → IconsCatalog}/settings.debug.svg +1 -1
  7. package/dist/{Accordion/IconsLib → IconsCatalog}/settings.save.svg +5 -4
  8. package/dist/Input/Input.svelte +1 -1
  9. package/dist/Joystick/Joystick.svelte +97 -0
  10. package/dist/Joystick/Joystick.svelte.d.ts +4 -0
  11. package/dist/Joystick/JoystickProps.svelte +0 -0
  12. package/dist/Joystick/JoystickProps.svelte.d.ts +26 -0
  13. package/dist/ProgressBar/ProgressBar.svelte +4 -6
  14. package/dist/Table/Table.svelte +10 -6
  15. package/dist/Table/TableProps.svelte +223 -145
  16. package/dist/Tabs/Tabs.svelte +86 -0
  17. package/dist/Tabs/Tabs.svelte.d.ts +4 -0
  18. package/dist/Tabs/TabsProps.svelte +349 -0
  19. package/dist/Tabs/TabsProps.svelte.d.ts +11 -0
  20. package/dist/TextField/TextFieldProps.svelte +3 -9
  21. package/dist/{Accordion/icons.js → icons.js} +22 -22
  22. package/dist/index.d.ts +3 -1
  23. package/dist/index.js +4 -0
  24. package/dist/locales/translations.js +8 -5
  25. package/dist/options.d.ts +10 -0
  26. package/dist/options.js +11 -0
  27. package/dist/types.d.ts +22 -6
  28. package/package.json +9 -9
  29. /package/dist/{Accordion/IconsLib → IconsCatalog}/access.card.svg +0 -0
  30. /package/dist/{Accordion/IconsLib → IconsCatalog}/access.key.svg +0 -0
  31. /package/dist/{Accordion/IconsLib → IconsCatalog}/access.lock.svg +0 -0
  32. /package/dist/{Accordion/IconsLib → IconsCatalog}/common.battery.svg +0 -0
  33. /package/dist/{Accordion/IconsLib → IconsCatalog}/common.block.svg +0 -0
  34. /package/dist/{Accordion/IconsLib → IconsCatalog}/common.list.svg +0 -0
  35. /package/dist/{Accordion/IconsLib → IconsCatalog}/common.search.svg +0 -0
  36. /package/dist/{Accordion/IconsLib → IconsCatalog}/common.trash.svg +0 -0
  37. /package/dist/{Accordion/IconsLib → IconsCatalog}/common.warning.svg +0 -0
  38. /package/dist/{Accordion/IconsLib → IconsCatalog}/iconsLib.d.ts +0 -0
  39. /package/dist/{Accordion/IconsLib → IconsCatalog}/info.bell.svg +0 -0
  40. /package/dist/{Accordion/IconsLib → IconsCatalog}/info.clock.svg +0 -0
  41. /package/dist/{Accordion/IconsLib → IconsCatalog}/info.graph.svg +0 -0
  42. /package/dist/{Accordion/IconsLib → IconsCatalog}/info.info.svg +0 -0
  43. /package/dist/{Accordion/IconsLib/image.camera.svg → IconsCatalog/media.camera.svg} +0 -0
  44. /package/dist/{Accordion/IconsLib/image.movie.svg → IconsCatalog/media.movie.svg} +0 -0
  45. /package/dist/{Accordion/IconsLib/electronic.sound.svg → IconsCatalog/media.sound.svg} +0 -0
  46. /package/dist/{Accordion/IconsLib/image.webcam.svg → IconsCatalog/media.webcam.svg} +0 -0
  47. /package/dist/{Accordion/IconsLib → IconsCatalog}/network.cellular.svg +0 -0
  48. /package/dist/{Accordion/IconsLib → IconsCatalog}/network.cloud.svg +0 -0
  49. /package/dist/{Accordion/IconsLib → IconsCatalog}/network.globe.svg +0 -0
  50. /package/dist/{Accordion/IconsLib → IconsCatalog}/network.link.svg +0 -0
  51. /package/dist/{Accordion/IconsLib → IconsCatalog}/network.radio.svg +0 -0
  52. /package/dist/{Accordion/IconsLib → IconsCatalog}/network.share.svg +0 -0
  53. /package/dist/{Accordion/IconsLib → IconsCatalog}/network.wifi.svg +0 -0
  54. /package/dist/{Accordion/IconsLib/electronic.board.svg → IconsCatalog/periphery.board.svg} +0 -0
  55. /package/dist/{Accordion/IconsLib/electronic.chip.svg → IconsCatalog/periphery.chip.svg} +0 -0
  56. /package/dist/{Accordion/IconsLib/electronic.magnit.svg → IconsCatalog/periphery.magnit.svg} +0 -0
  57. /package/dist/{Accordion/IconsLib/electronic.memory.svg → IconsCatalog/periphery.memory.svg} +0 -0
  58. /package/dist/{Accordion/IconsLib/electronic.volume.svg → IconsCatalog/periphery.volume.svg} +0 -0
  59. /package/dist/{Accordion/IconsLib → IconsCatalog}/power.jeck.svg +0 -0
  60. /package/dist/{Accordion/IconsLib → IconsCatalog}/power.power.svg +0 -0
  61. /package/dist/{Accordion/IconsLib/control.point.svg → IconsCatalog/scenarios.point.svg} +0 -0
  62. /package/dist/{Accordion/IconsLib/control.speed.svg → IconsCatalog/scenarios.speed.svg} +0 -0
  63. /package/dist/{Accordion/IconsLib → IconsCatalog}/settings.hammer.svg +0 -0
  64. /package/dist/{Accordion/IconsLib → IconsCatalog}/settings.list.svg +0 -0
  65. /package/dist/{Accordion/IconsLib → IconsCatalog}/settings.settings.svg +0 -0
  66. /package/dist/{Accordion/IconsLib → IconsCatalog}/settings.spanner.svg +0 -0
  67. /package/dist/{Accordion/IconsLib/electronic.terminal.svg → IconsCatalog/settings.terminal.svg} +0 -0
  68. /package/dist/{Accordion/icons.d.ts → icons.d.ts} +0 -0
@@ -7,6 +7,9 @@
7
7
  import ButtonAdd from '../libIcons/ButtonAdd.svelte'
8
8
  import { optionsStore } from '../options'
9
9
  import { twMerge } from 'tailwind-merge'
10
+ import Modal from '../Modal.svelte'
11
+ import { ICONS } from '../icons'
12
+ import CrossIcon from '../libIcons/CrossIcon.svelte'
10
13
 
11
14
  const {
12
15
  component,
@@ -21,6 +24,8 @@
21
24
  const DeviceVariables = getContext<{ id: string; value: string; name: string }[]>('DeviceVariables')
22
25
  let VARIABLE_OPTIONS = $derived(DeviceVariables && Array.isArray(DeviceVariables) ? DeviceVariables : [])
23
26
 
27
+ let defaultIcon = $state({ isModalOpen: false, columnIndex: 0, column: component.properties.header[0] })
28
+
24
29
  const initialColor = $derived(
25
30
  $optionsStore.COLOR_OPTIONS.find((c) =>
26
31
  (c.value as string).includes(component.properties.wrapperClass?.split(' ').find((cls: string) => cls.startsWith('bg-'))),
@@ -331,6 +336,7 @@
331
336
  label: { name: `Column ${(component.properties.header?.length || 0) + 1}`, class: '' },
332
337
  width: '10%',
333
338
  sortable: false,
339
+ image: { width: '0rem', height: '0rem' },
334
340
  }
335
341
  const headers = [...(component.properties.header || []), newColumn]
336
342
  updateProperty('header', headers, component, onPropertyChange)
@@ -338,167 +344,239 @@
338
344
  }}
339
345
  />
340
346
  </div>
341
-
342
- {#each component.properties.header as column, columnIndex (columnIndex)}
343
- <div class="mb-5">
344
- <div class="mr-2 flex items-end justify-around gap-6">
345
- <UI.Input
346
- label={{ name: $t('constructor.props.table.columns.key') }}
347
- wrapperClass="w-150"
348
- value={column.key}
349
- help={{ regExp: /^[0-9a-zA-Z_-]{0,16}$/ }}
350
- onUpdate={(value) => {
351
- updateTableHeader(columnIndex, 'key', value)
352
- updateTableBody()
353
- }}
354
- />
355
- <UI.Input
356
- label={{ name: $t('constructor.props.table.columns.label') }}
357
- value={column.label.name}
358
- onUpdate={(value) => {
359
- updateTableHeader(columnIndex, 'label', { ['name']: value })
360
- }}
361
- />
362
- <UI.Input
363
- label={{ name: $t('constructor.props.table.columns.width'), class: 'px-0' }}
364
- wrapperClass="w-150"
365
- type="number"
366
- value={Number(column.width.replace('%', ''))}
367
- onUpdate={(value) => updateTableHeader(columnIndex, 'width', `${value}%`)}
368
- />
369
- <UI.Select
370
- label={{ name: $t('constructor.props.align.header') }}
371
- type="buttons"
372
- value={$optionsStore.ALIGN_OPTIONS.find((a) => (a.value as string).includes(column.align?.header) || 'left')}
373
- options={$optionsStore.ALIGN_OPTIONS}
374
- onUpdate={(option) => updateTableHeader(columnIndex, 'align', { header: option.value, content: column.align?.content })}
375
- />
376
- <UI.Switch
377
- label={{ name: $t('constructor.props.table.columns.sortable'), class: 'px-0' }}
378
- wrapperClass="w-30"
379
- value={column.sortable ? 2 : 1}
380
- onChange={(value) => updateTableHeader(columnIndex, 'sortable', value === 2)}
381
- />
382
- <UI.Switch
383
- label={{ name: $t('constructor.props.copy'), class: 'px-0' }}
384
- wrapperClass="w-30"
385
- value={column.overflow?.copy ? 2 : 1}
386
- onChange={(value) => updateTableHeader(columnIndex, 'overflow', { copy: value === 2, truncated: column.overflow?.truncated })}
387
- />
388
- <UI.Button
389
- wrapperClass="w-8"
390
- content={{ icon: ButtonAdd, info: { text: $t('constructor.props.table.addaction'), side: 'top' } }}
391
- onClick={() => {
392
- const newButton = {
393
- name: `button${(component.properties.header[columnIndex].buttons ? component.properties.header[columnIndex].buttons.length : 0) + 1}`,
394
- class: 'bg-blue',
395
- eventHandler: { Header: 'SET', Argument: 'Save', Variables: [] },
396
- onClick: () => {},
397
- }
398
- const buttons = [...(component.properties.header[columnIndex].buttons || []), newButton]
399
- updateTableHeader(columnIndex, 'buttons', buttons)
400
- }}
401
- />
402
- <UI.Button
403
- wrapperClass="w-8"
404
- content={{ icon: ButtonDelete }}
405
- onClick={() => {
406
- const headers = [...(component.properties.header || [])]
407
- headers.splice(columnIndex, 1)
408
- updateProperty('header', headers, component, onPropertyChange)
409
- }}
410
- />
411
- </div>
412
- <div class="mr-2 flex items-end justify-around gap-6">
413
- <UI.Select
414
- label={{ name: $t('constructor.props.align.content') }}
415
- type="buttons"
416
- value={$optionsStore.ALIGN_OPTIONS.find((a) => (a.value as string).includes(column.align?.content) || 'left')}
417
- options={$optionsStore.ALIGN_OPTIONS}
418
- onUpdate={(option) => updateTableHeader(columnIndex, 'align', { header: column.align?.header, content: option.value })}
419
- />
420
- <UI.Switch
421
- wrapperClass="w-2/10"
422
- label={{ name: $t('constructor.props.table.columns.truncated') }}
423
- value={column.overflow?.truncated ? 2 : 1}
424
- onChange={(value) => updateTableHeader(columnIndex, 'overflow', { truncated: value === 2, copy: column.overflow?.copy })}
425
- />
426
-
427
- <UI.Input
428
- label={{ name: $t('constructor.props.table.columns.class') }}
429
- value={column.image?.class}
430
- onUpdate={(value) => {
431
- updateTableHeader(columnIndex, 'image', { class: value, width: column.image?.width, height: column.image?.height })
432
- }}
433
- />
434
- <UI.Input
435
- label={{ name: $t('constructor.props.table.columns.image.width'), class: 'px-0' }}
436
- wrapperClass="w-150"
437
- value={column.image?.width}
438
- onUpdate={(value) => {
439
- updateTableHeader(columnIndex, 'image', { class: column.image?.class, width: value, height: column.image?.height })
440
- }}
441
- />
442
- <UI.Input
443
- label={{ name: $t('constructor.props.table.columns.image.height'), class: 'px-0' }}
444
- wrapperClass="w-150"
445
- value={column.image?.height}
446
- onUpdate={(value) => {
447
- updateTableHeader(columnIndex, 'image', { class: column.image?.class, width: column.image?.width, height: value })
448
- }}
449
- />
450
- </div>
451
- </div>
452
-
453
- {#if column.buttons && column.buttons.length > 0}
454
- <div class="mb-5 rounded-lg p-1">
455
- {#each column.buttons as button, buttonIndex (buttonIndex)}
456
- <div class="mx-14 flex items-end justify-around gap-2">
347
+ <div class="flex flex-col gap-2">
348
+ {#each component.properties.header as column, columnIndex (columnIndex)}
349
+ <div class="rounded-2xl border border-(--border-color) p-2">
350
+ <div class="mb-5">
351
+ <div class="mr-2 flex items-end justify-around gap-6">
457
352
  <UI.Input
458
- label={{ name: $t('constructor.props.name') }}
459
- wrapperClass="!w-3/10"
460
- value={button.name}
461
- onUpdate={(value) => updateButtonProperty(columnIndex, buttonIndex, 'name', value)}
353
+ label={{ name: $t('constructor.props.table.columns.key') }}
354
+ wrapperClass="w-150"
355
+ value={column.key}
356
+ help={{ regExp: /^[0-9a-zA-Z_-]{0,16}$/ }}
357
+ onUpdate={(value) => {
358
+ updateTableHeader(columnIndex, 'key', value)
359
+ updateTableBody()
360
+ }}
361
+ />
362
+ <UI.Input
363
+ label={{ name: $t('constructor.props.table.columns.label') }}
364
+ value={column.label.name}
365
+ onUpdate={(value) => {
366
+ updateTableHeader(columnIndex, 'label', { ['name']: value })
367
+ }}
368
+ />
369
+ <UI.Input
370
+ label={{ name: $t('constructor.props.table.columns.width'), class: 'px-0' }}
371
+ wrapperClass="w-150"
372
+ type="number"
373
+ value={Number(column.width.replace('%', ''))}
374
+ onUpdate={(value) => updateTableHeader(columnIndex, 'width', `${value}%`)}
462
375
  />
463
376
  <UI.Select
464
- wrapperClass="!w-2/10"
465
- label={{ name: $t('constructor.props.header') }}
377
+ label={{ name: $t('constructor.props.align.header') }}
466
378
  type="buttons"
467
- value={$optionsStore.HEADER_OPTIONS.find((h) => h.value === button.eventHandler?.Header)}
468
- options={$optionsStore.HEADER_OPTIONS}
469
- onUpdate={(option) => {
470
- const handler = button.eventHandler
471
- handler.Header = option.value as string
472
- updateButtonProperty(columnIndex, buttonIndex, 'eventHandler', handler)
379
+ value={$optionsStore.ALIGN_OPTIONS.find((a) => (a.value as string).includes(column.align?.header) || 'left')}
380
+ options={$optionsStore.ALIGN_OPTIONS}
381
+ onUpdate={(option) => updateTableHeader(columnIndex, 'align', { header: option.value, content: column.align?.content })}
382
+ />
383
+ <UI.Switch
384
+ label={{ name: $t('constructor.props.table.columns.sortable'), class: 'px-0' }}
385
+ wrapperClass="w-30"
386
+ value={column.sortable ? 2 : 1}
387
+ onChange={(value) => updateTableHeader(columnIndex, 'sortable', value === 2)}
388
+ />
389
+ <UI.Switch
390
+ label={{ name: $t('constructor.props.copy'), class: 'px-0' }}
391
+ wrapperClass="w-30"
392
+ value={column.overflow?.copy ? 2 : 1}
393
+ onChange={(value) => updateTableHeader(columnIndex, 'overflow', { copy: value === 2, truncated: column.overflow?.truncated })}
394
+ />
395
+ <UI.Button
396
+ wrapperClass="w-8"
397
+ content={{ icon: ButtonAdd, info: { text: $t('constructor.props.table.addaction'), side: 'top' } }}
398
+ onClick={() => {
399
+ const newButton = {
400
+ name: `button${(component.properties.header[columnIndex].buttons ? component.properties.header[columnIndex].buttons.length : 0) + 1}`,
401
+ class: 'bg-blue',
402
+ eventHandler: { Header: 'SET', Argument: 'Save', Variables: [] },
403
+ onClick: () => {},
404
+ }
405
+ const buttons = [...(component.properties.header[columnIndex].buttons || []), newButton]
406
+ updateTableHeader(columnIndex, 'buttons', buttons)
473
407
  }}
474
408
  />
409
+ <UI.Button
410
+ wrapperClass="w-8"
411
+ content={{ icon: ButtonDelete }}
412
+ onClick={() => {
413
+ const headers = [...(component.properties.header || [])]
414
+ headers.splice(columnIndex, 1)
415
+ updateProperty('header', headers, component, onPropertyChange)
416
+ }}
417
+ />
418
+ </div>
419
+ <div class="mr-2 flex items-end justify-around gap-6">
420
+ <UI.Select
421
+ label={{ name: $t('constructor.props.align.content') }}
422
+ type="buttons"
423
+ value={$optionsStore.ALIGN_OPTIONS.find((a) => (a.value as string).includes(column.align?.content) || 'left')}
424
+ options={$optionsStore.ALIGN_OPTIONS}
425
+ onUpdate={(option) => updateTableHeader(columnIndex, 'align', { header: column.align?.header, content: option.value })}
426
+ />
427
+ <UI.Switch
428
+ wrapperClass="w-2/10"
429
+ label={{ name: $t('constructor.props.table.columns.truncated') }}
430
+ value={column.overflow?.truncated ? 2 : 1}
431
+ onChange={(value) => updateTableHeader(columnIndex, 'overflow', { truncated: value === 2, copy: column.overflow?.copy })}
432
+ />
433
+ <div class="relative mt-6 flex w-full gap-2">
434
+ <UI.Button
435
+ content={{ name: $t('constructor.props.table.columns.defaultIcon') }}
436
+ onClick={() => (defaultIcon = { isModalOpen: true, columnIndex: columnIndex, column: column })}
437
+ />
438
+ {#if column.image?.defaultIcon}
439
+ <UI.Button
440
+ wrapperClass="w-8.5 "
441
+ componentClass="p-0.5 bg-red"
442
+ content={{ icon: CrossIcon }}
443
+ onClick={() => {
444
+ updateTableHeader(columnIndex, 'image', {
445
+ class: column.image?.class,
446
+ width: column.image?.width,
447
+ height: column.image?.height,
448
+ defaultIcon: '',
449
+ })
450
+ }}
451
+ />
452
+ {/if}
453
+ </div>
475
454
  <UI.Input
476
- wrapperClass="!w-2/10"
477
- label={{ name: $t('constructor.props.argument') }}
478
- value={button.eventHandler?.Argument}
455
+ label={{ name: $t('constructor.props.table.columns.class') }}
456
+ value={column.image?.class}
479
457
  onUpdate={(value) => {
480
- const handler = button.eventHandler
481
- handler.Argument = value as string
482
- updateButtonProperty(columnIndex, buttonIndex, 'eventHandler', handler)
458
+ updateTableHeader(columnIndex, 'image', {
459
+ class: value,
460
+ width: column.image?.width,
461
+ height: column.image?.height,
462
+ defaultIcon: column.image.defaultIcon,
463
+ })
483
464
  }}
484
465
  />
485
466
  <UI.Input
486
- wrapperClass="!w-2/10"
487
- label={{ name: $t('constructor.props.table.keys') }}
488
- value={button.eventHandler?.Variables.join(' ')}
489
- maxlength={500}
490
- help={{ info: $t('constructor.props.table.keys.info'), regExp: /^[a-zA-Z0-9\-_ ]{0,500}$/ }}
467
+ label={{ name: $t('constructor.props.table.columns.image.width'), class: 'px-0' }}
468
+ type="number"
469
+ number={{ minNum: 0, maxNum: 1000, step: 1 }}
470
+ wrapperClass="w-150"
471
+ value={Number(column.image?.width.replace('rem', '')) ?? 0}
491
472
  onUpdate={(value) => {
492
- const handler = { ...button.eventHandler }
493
- handler.Variables = (value as string).trim().split(/\s+/)
494
- updateButtonProperty(columnIndex, buttonIndex, 'eventHandler', handler)
473
+ updateTableHeader(columnIndex, 'image', {
474
+ class: column.image?.class,
475
+ width: `${value ?? 0}rem`,
476
+ height: column.image?.height,
477
+ defaultIcon: column.image.defaultIcon,
478
+ })
479
+ }}
480
+ />
481
+ <UI.Input
482
+ label={{ name: $t('constructor.props.table.columns.image.height'), class: 'px-0' }}
483
+ type="number"
484
+ number={{ minNum: 0, maxNum: 1000, step: 1 }}
485
+ wrapperClass="w-150"
486
+ value={Number(column.image?.height.replace('rem', ''))}
487
+ onUpdate={(value) => {
488
+ updateTableHeader(columnIndex, 'image', {
489
+ class: column.image?.class,
490
+ width: column.image?.width,
491
+ height: `${value}rem`,
492
+ defaultIcon: column.image.defaultIcon,
493
+ })
495
494
  }}
496
495
  />
497
- <UI.Button wrapperClass="w-8" content={{ icon: ButtonDelete }} onClick={() => removeButtonFromColumn(columnIndex, buttonIndex)} />
498
496
  </div>
499
- {/each}
497
+ </div>
498
+
499
+ {#if column.buttons && column.buttons.length > 0}
500
+ <hr class="border-(--border-color)" />
501
+ <div class="mb-5 rounded-lg p-1">
502
+ {#each column.buttons as button, buttonIndex (buttonIndex)}
503
+ <div class="ml-14 flex items-end justify-between gap-2">
504
+ <UI.Input
505
+ label={{ name: $t('constructor.props.name') }}
506
+ wrapperClass="!w-3/10"
507
+ value={button.name}
508
+ onUpdate={(value) => updateButtonProperty(columnIndex, buttonIndex, 'name', value)}
509
+ />
510
+ <UI.Select
511
+ wrapperClass="!w-2/10"
512
+ label={{ name: $t('constructor.props.header') }}
513
+ type="buttons"
514
+ value={$optionsStore.HEADER_OPTIONS.find((h) => h.value === button.eventHandler?.Header)}
515
+ options={$optionsStore.HEADER_OPTIONS}
516
+ onUpdate={(option) => {
517
+ const handler = button.eventHandler
518
+ handler.Header = option.value as string
519
+ updateButtonProperty(columnIndex, buttonIndex, 'eventHandler', handler)
520
+ }}
521
+ />
522
+ <UI.Input
523
+ wrapperClass="!w-2/10"
524
+ label={{ name: $t('constructor.props.argument') }}
525
+ value={button.eventHandler?.Argument}
526
+ onUpdate={(value) => {
527
+ const handler = button.eventHandler
528
+ handler.Argument = value as string
529
+ updateButtonProperty(columnIndex, buttonIndex, 'eventHandler', handler)
530
+ }}
531
+ />
532
+ <UI.Input
533
+ wrapperClass="!w-2/10"
534
+ label={{ name: $t('constructor.props.table.keys') }}
535
+ value={button.eventHandler?.Variables.join(' ')}
536
+ maxlength={500}
537
+ help={{ info: $t('constructor.props.table.keys.info'), regExp: /^[a-zA-Z0-9\-_ ]{0,500}$/ }}
538
+ onUpdate={(value) => {
539
+ const handler = { ...button.eventHandler }
540
+ handler.Variables = (value as string).trim().split(/\s+/)
541
+ updateButtonProperty(columnIndex, buttonIndex, 'eventHandler', handler)
542
+ }}
543
+ />
544
+ <UI.Button wrapperClass="w-8" content={{ icon: ButtonDelete }} onClick={() => removeButtonFromColumn(columnIndex, buttonIndex)} />
545
+ </div>
546
+ {/each}
547
+ </div>
548
+ {/if}
500
549
  </div>
550
+ {/each}
551
+ {#if defaultIcon.isModalOpen}
552
+ <Modal bind:isOpen={defaultIcon.isModalOpen} wrapperClass="w-130">
553
+ {#snippet main()}
554
+ <div class="grid grid-cols-3">
555
+ {#each ICONS as category}
556
+ <div class="relative m-1.5 rounded-xl border-2 border-(--border-color) p-3">
557
+ <div class="absolute -top-3.5 bg-(--back-color) px-1">{$t(`constructor.props.icon.${category[0]}`)}</div>
558
+ <div class="grid grid-cols-3 place-items-center gap-2">
559
+ {#each category[1] as icon}
560
+ <button
561
+ class="h-8 w-8 cursor-pointer [&_svg]:h-full [&_svg]:max-h-full [&_svg]:w-full [&_svg]:max-w-full"
562
+ onclick={() => {
563
+ updateTableHeader(defaultIcon.columnIndex, 'image', {
564
+ class: defaultIcon.column.image?.class,
565
+ width: defaultIcon.column.image?.width,
566
+ height: defaultIcon.column.image?.height,
567
+ defaultIcon: icon as string,
568
+ })
569
+ }}
570
+ >
571
+ {@html icon}
572
+ </button>{/each}
573
+ </div>
574
+ </div>
575
+ {/each}
576
+ </div>
577
+ {/snippet}
578
+ </Modal>
501
579
  {/if}
502
- {/each}
580
+ </div>
503
581
  </div>
504
582
  {/if}
@@ -0,0 +1,86 @@
1
+ <script lang="ts">
2
+ import type { ITabsProps } from '../types'
3
+ import { onMount } from 'svelte'
4
+ import { twMerge } from 'tailwind-merge'
5
+
6
+ let {
7
+ id = crypto.randomUUID(),
8
+ wrapperClass = '',
9
+ size = { width: 12, height: 6 },
10
+ activeTab = 0,
11
+ items = [
12
+ {
13
+ name: 'tab 1',
14
+ icon: '<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24"\r\n ><path\r\n fill="none"\r\n stroke="currentColor"\r\n stroke-linecap="round"\r\n stroke-linejoin="round"\r\n stroke-width="1.5"\r\n d="M14.44 5.78L4.198 16.02a2 2 0 0 0-.565 1.125l-.553 3.774l3.775-.553A2 2 0 0 0 7.98 19.8L18.22 9.56m-3.78-3.78l2.229-2.23a1.6 1.6 0 0 1 2.263 0l1.518 1.518a1.6 1.6 0 0 1 0 2.263l-2.23 2.23M14.44 5.78l3.78 3.78"\r\n /></svg\r\n>\r\n',
15
+ class: '',
16
+ },
17
+ { name: 'tab 2', icon: '', class: 'bg-red' },
18
+ ],
19
+ apiArray = [],
20
+ Components,
21
+ }: ITabsProps = $props()
22
+
23
+ const isCol = $derived(items.find((item) => item.class?.startsWith('flex-col')))
24
+
25
+ let currentTabIndex: number = $state(activeTab)
26
+ </script>
27
+
28
+ <div {id} class="w-full rounded-2xl bg-(--back-color)">
29
+ <!-- Вкладки -->
30
+ <div
31
+ class="{twMerge('bg-blue sticky top-0 z-50 flex h-fit items-center overflow-x-auto rounded-t-2xl px-1 pt-1', wrapperClass)}
32
+ bg-(--bg-color)"
33
+ >
34
+ {#each items as item, index}
35
+ <button
36
+ class={twMerge(
37
+ `tab mt-1 flex min-w-fit cursor-pointer items-center justify-center gap-0 self-end rounded-t-2xl px-5 py-2.5 ${!isCol && 'gap-2'}`,
38
+ item.class,
39
+ index === currentTabIndex ? twMerge('bg-(--back-color) text-blue-500', item.class) : 'bg-(--bg-color) text-gray-500',
40
+ )}
41
+ onclick={() => (currentTabIndex = index)}
42
+ >
43
+ {#if item?.icon}
44
+ <span class="flex h-7 w-7 items-center justify-center overflow-visible [&_svg]:h-full [&_svg]:max-h-full [&_svg]:w-full [&_svg]:max-w-full">
45
+ {@html item.icon}
46
+ </span>
47
+ {/if}
48
+ {#if item?.name}
49
+ <span class="text-lg font-semibold">{item.name}</span>
50
+ {/if}
51
+ </button>
52
+ <span
53
+ class="h-[{isCol && items.find((item) => item.icon) ? 35 : 16}px] w-0 border border-l {index !== items.length - 1 &&
54
+ index !== currentTabIndex &&
55
+ index !== currentTabIndex - 1
56
+ ? 'border-gray-500'
57
+ : 'border-(--bg-color)'}"
58
+ ></span>
59
+ {/each}
60
+ </div>
61
+
62
+ <!-- Контент вкладки -->
63
+ <div
64
+ class="grid w-full gap-2 rounded-2xl bg-(--back-color) p-4"
65
+ style="grid-template-columns: repeat({size.width || 1}, minmax(0, 1fr)); grid-template-rows: repeat({size.height || 1}, auto);"
66
+ >
67
+ {#if Components}
68
+ {#each (apiArray ?? []).filter((c) => c.id.endsWith(`${currentTabIndex}`)) as comp}
69
+ {@render Components(comp, false)}
70
+ {/each}
71
+ {:else}
72
+ {@render items[currentTabIndex]?.children?.()}
73
+ {/if}
74
+ </div>
75
+ </div>
76
+
77
+ <style>
78
+ ::-webkit-scrollbar-track {
79
+ background: var(--back-color);
80
+ }
81
+ ::-webkit-scrollbar-thumb {
82
+ background-color: color-mix(in srgb, var(--bg-color), var(--back-color) 20%);
83
+ border-radius: 8px;
84
+ cursor: pointer;
85
+ }
86
+ </style>
@@ -0,0 +1,4 @@
1
+ import type { ITabsProps } from '../types';
2
+ declare const Tabs: import("svelte").Component<ITabsProps, {}, "">;
3
+ type Tabs = ReturnType<typeof Tabs>;
4
+ export default Tabs;