@juspay/svelte-ui-components 2.9.0 → 2.11.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 (189) hide show
  1. package/README.md +337 -77
  2. package/dist/Accordion/Accordion.svelte +4 -2
  3. package/dist/Accordion/Accordion.svelte.d.ts +2 -4
  4. package/dist/Accordion/properties.d.ts +6 -0
  5. package/dist/Accordion/properties.js +1 -0
  6. package/dist/Animations/ModalAnimation.svelte +11 -9
  7. package/dist/Avatar/Avatar.svelte +122 -0
  8. package/dist/Avatar/Avatar.svelte.d.ts +4 -0
  9. package/dist/Avatar/properties.d.ts +15 -0
  10. package/dist/Avatar/properties.js +1 -0
  11. package/dist/Badge/Badge.svelte +2 -2
  12. package/dist/Badge/properties.d.ts +1 -0
  13. package/dist/Banner/Banner.svelte +132 -48
  14. package/dist/Banner/Banner.svelte.d.ts +1 -1
  15. package/dist/Banner/properties.d.ts +8 -3
  16. package/dist/Book/Book.svelte +281 -0
  17. package/dist/Book/Book.svelte.d.ts +4 -0
  18. package/dist/Book/properties.d.ts +24 -0
  19. package/dist/Book/properties.js +1 -0
  20. package/dist/BrandLoader/BrandLoader.svelte +3 -3
  21. package/dist/BrandLoader/properties.d.ts +1 -0
  22. package/dist/Browser/Browser.svelte +193 -0
  23. package/dist/Browser/Browser.svelte.d.ts +3 -0
  24. package/dist/Browser/properties.d.ts +16 -0
  25. package/dist/Browser/properties.js +1 -0
  26. package/dist/Button/Button.svelte +20 -7
  27. package/dist/Button/properties.d.ts +7 -4
  28. package/dist/Calendar/Calendar.svelte +476 -0
  29. package/dist/Calendar/Calendar.svelte.d.ts +4 -0
  30. package/dist/Calendar/properties.d.ts +30 -0
  31. package/dist/Calendar/properties.js +1 -0
  32. package/dist/Carousel/Carousel.svelte +19 -16
  33. package/dist/Carousel/properties.d.ts +1 -0
  34. package/dist/CheckListItem/CheckListItem.svelte +31 -26
  35. package/dist/CheckListItem/properties.d.ts +4 -1
  36. package/dist/Checkbox/Checkbox.svelte +157 -0
  37. package/dist/Checkbox/Checkbox.svelte.d.ts +4 -0
  38. package/dist/Checkbox/properties.d.ts +17 -0
  39. package/dist/Checkbox/properties.js +1 -0
  40. package/dist/Choicebox/Choicebox.svelte +85 -0
  41. package/dist/Choicebox/Choicebox.svelte.d.ts +4 -0
  42. package/dist/Choicebox/properties.d.ts +14 -0
  43. package/dist/Choicebox/properties.js +1 -0
  44. package/dist/CommandMenu/CommandMenu.svelte +452 -0
  45. package/dist/CommandMenu/CommandMenu.svelte.d.ts +4 -0
  46. package/dist/CommandMenu/properties.d.ts +26 -0
  47. package/dist/CommandMenu/properties.js +1 -0
  48. package/dist/ContextMenu/ContextMenu.svelte +308 -0
  49. package/dist/ContextMenu/ContextMenu.svelte.d.ts +4 -0
  50. package/dist/ContextMenu/properties.d.ts +26 -0
  51. package/dist/ContextMenu/properties.js +1 -0
  52. package/dist/Gauge/Gauge.svelte +70 -0
  53. package/dist/Gauge/Gauge.svelte.d.ts +4 -0
  54. package/dist/Gauge/properties.d.ts +9 -0
  55. package/dist/Gauge/properties.js +1 -0
  56. package/dist/GridItem/GridItem.svelte +5 -4
  57. package/dist/GridItem/properties.d.ts +1 -0
  58. package/dist/Icon/Icon.svelte +3 -3
  59. package/dist/Icon/properties.d.ts +1 -0
  60. package/dist/IconStack/IconStack.svelte +3 -3
  61. package/dist/IconStack/properties.d.ts +1 -0
  62. package/dist/Img/Img.svelte +5 -3
  63. package/dist/Img/properties.d.ts +5 -1
  64. package/dist/Input/Input.svelte +12 -6
  65. package/dist/Input/properties.d.ts +1 -0
  66. package/dist/InputButton/InputButton.svelte +4 -3
  67. package/dist/InputButton/properties.d.ts +5 -6
  68. package/dist/KeyboardInput/KeyboardInput.svelte +93 -0
  69. package/dist/KeyboardInput/KeyboardInput.svelte.d.ts +4 -0
  70. package/dist/KeyboardInput/properties.d.ts +12 -0
  71. package/dist/KeyboardInput/properties.js +1 -0
  72. package/dist/ListItem/ListItem.svelte +31 -28
  73. package/dist/ListItem/properties.d.ts +1 -0
  74. package/dist/Loader/Loader.svelte +10 -6
  75. package/dist/Loader/Loader.svelte.d.ts +3 -25
  76. package/dist/Loader/properties.d.ts +3 -0
  77. package/dist/Loader/properties.js +1 -0
  78. package/dist/LoadingDots/LoadingDots.svelte +64 -0
  79. package/dist/LoadingDots/LoadingDots.svelte.d.ts +3 -0
  80. package/dist/LoadingDots/properties.d.ts +8 -0
  81. package/dist/LoadingDots/properties.js +1 -0
  82. package/dist/Menu/Menu.svelte +349 -0
  83. package/dist/Menu/Menu.svelte.d.ts +4 -0
  84. package/dist/Menu/properties.d.ts +24 -0
  85. package/dist/Menu/properties.js +1 -0
  86. package/dist/Modal/Modal.svelte +10 -9
  87. package/dist/Modal/properties.d.ts +1 -0
  88. package/dist/Pagination/Pagination.svelte +152 -0
  89. package/dist/Pagination/Pagination.svelte.d.ts +4 -0
  90. package/dist/Pagination/properties.d.ts +14 -0
  91. package/dist/Pagination/properties.js +1 -0
  92. package/dist/Phone/Phone.svelte +234 -0
  93. package/dist/Phone/Phone.svelte.d.ts +3 -0
  94. package/dist/Phone/properties.d.ts +11 -0
  95. package/dist/Phone/properties.js +1 -0
  96. package/dist/Pill/Pill.svelte +130 -0
  97. package/dist/Pill/Pill.svelte.d.ts +4 -0
  98. package/dist/Pill/properties.d.ts +16 -0
  99. package/dist/Pill/properties.js +1 -0
  100. package/dist/Progress/Progress.svelte +68 -0
  101. package/dist/Progress/Progress.svelte.d.ts +4 -0
  102. package/dist/Progress/properties.d.ts +10 -0
  103. package/dist/Progress/properties.js +1 -0
  104. package/dist/Radio/Radio.svelte +128 -0
  105. package/dist/Radio/Radio.svelte.d.ts +4 -0
  106. package/dist/Radio/properties.d.ts +15 -0
  107. package/dist/Radio/properties.js +1 -0
  108. package/dist/RelativeTime/RelativeTime.svelte +117 -0
  109. package/dist/RelativeTime/RelativeTime.svelte.d.ts +4 -0
  110. package/dist/RelativeTime/properties.d.ts +13 -0
  111. package/dist/RelativeTime/properties.js +1 -0
  112. package/dist/Scroller/Scroller.svelte +389 -0
  113. package/dist/Scroller/Scroller.svelte.d.ts +4 -0
  114. package/dist/Scroller/properties.d.ts +30 -0
  115. package/dist/Scroller/properties.js +1 -0
  116. package/dist/Select/Select.svelte +382 -344
  117. package/dist/Select/Select.svelte.d.ts +1 -1
  118. package/dist/Select/properties.d.ts +16 -26
  119. package/dist/Sheet/Sheet.svelte +264 -0
  120. package/dist/Sheet/Sheet.svelte.d.ts +4 -0
  121. package/dist/Sheet/properties.d.ts +19 -0
  122. package/dist/Sheet/properties.js +1 -0
  123. package/dist/Shimmer/Shimmer.svelte +44 -0
  124. package/dist/Shimmer/Shimmer.svelte.d.ts +4 -0
  125. package/dist/Shimmer/properties.d.ts +4 -0
  126. package/dist/Shimmer/properties.js +1 -0
  127. package/dist/Slider/Slider.svelte +144 -0
  128. package/dist/Slider/Slider.svelte.d.ts +4 -0
  129. package/dist/Slider/properties.d.ts +17 -0
  130. package/dist/Slider/properties.js +1 -0
  131. package/dist/Snippet/Snippet.svelte +123 -0
  132. package/dist/Snippet/Snippet.svelte.d.ts +4 -0
  133. package/dist/Snippet/properties.d.ts +15 -0
  134. package/dist/Snippet/properties.js +1 -0
  135. package/dist/SplitButton/SplitButton.svelte +135 -0
  136. package/dist/SplitButton/SplitButton.svelte.d.ts +4 -0
  137. package/dist/SplitButton/properties.d.ts +17 -0
  138. package/dist/SplitButton/properties.js +1 -0
  139. package/dist/Status/Status.svelte +5 -3
  140. package/dist/Status/properties.d.ts +1 -0
  141. package/dist/Stepper/Step.svelte +3 -3
  142. package/dist/Stepper/Stepper.svelte +3 -3
  143. package/dist/Stepper/properties.d.ts +2 -0
  144. package/dist/Table/Table.svelte +15 -8
  145. package/dist/Table/properties.d.ts +1 -0
  146. package/dist/Tabs/Tabs.svelte +240 -0
  147. package/dist/Tabs/Tabs.svelte.d.ts +4 -0
  148. package/dist/Tabs/properties.d.ts +16 -0
  149. package/dist/Tabs/properties.js +1 -0
  150. package/dist/ThemeSwitcher/ThemeSwitcher.svelte +249 -0
  151. package/dist/ThemeSwitcher/ThemeSwitcher.svelte.d.ts +4 -0
  152. package/dist/ThemeSwitcher/properties.d.ts +19 -0
  153. package/dist/ThemeSwitcher/properties.js +1 -0
  154. package/dist/Toast/Toast.svelte +25 -30
  155. package/dist/Toast/properties.d.ts +1 -0
  156. package/dist/Toggle/Toggle.svelte +2 -2
  157. package/dist/Toggle/properties.d.ts +1 -0
  158. package/dist/Toolbar/Toolbar.svelte +8 -7
  159. package/dist/Toolbar/properties.d.ts +1 -0
  160. package/dist/Tooltip/Tooltip.svelte +153 -0
  161. package/dist/Tooltip/Tooltip.svelte.d.ts +4 -0
  162. package/dist/Tooltip/properties.d.ts +13 -0
  163. package/dist/Tooltip/properties.js +1 -0
  164. package/dist/assets/battery.svg +5 -0
  165. package/dist/assets/checkmark.svg +3 -0
  166. package/dist/assets/chevron-down-sm.svg +3 -0
  167. package/dist/assets/chevron-down.svg +3 -0
  168. package/dist/assets/chevron-left-lg.svg +3 -0
  169. package/dist/assets/chevron-left.svg +3 -0
  170. package/dist/assets/chevron-right-lg.svg +3 -0
  171. package/dist/assets/chevron-right.svg +3 -0
  172. package/dist/assets/chevron-up.svg +3 -0
  173. package/dist/assets/close.svg +4 -0
  174. package/dist/assets/copy.svg +4 -0
  175. package/dist/assets/error-circle.svg +5 -0
  176. package/dist/assets/lock.svg +3 -0
  177. package/dist/assets/minus.svg +3 -0
  178. package/dist/assets/monitor.svg +5 -0
  179. package/dist/assets/moon.svg +3 -0
  180. package/dist/assets/palette.svg +7 -0
  181. package/dist/assets/search.svg +4 -0
  182. package/dist/assets/signal.svg +6 -0
  183. package/dist/assets/sun.svg +11 -0
  184. package/dist/assets/wifi.svg +3 -0
  185. package/dist/index.d.ts +55 -0
  186. package/dist/index.js +27 -0
  187. package/dist/utils.d.ts +2 -0
  188. package/dist/utils.js +18 -4
  189. package/package.json +26 -1
@@ -0,0 +1,4 @@
1
+ import type { SnippetProperties } from './properties';
2
+ declare const Snippet: import("svelte").Component<SnippetProperties, {}, "">;
3
+ type Snippet = ReturnType<typeof Snippet>;
4
+ export default Snippet;
@@ -0,0 +1,15 @@
1
+ import type { Snippet } from 'svelte';
2
+ export type SnippetProperties = MandatorySnippetProperties & OptionalSnippetProperties & SnippetEventProperties;
3
+ export type MandatorySnippetProperties = {
4
+ text: string;
5
+ };
6
+ export type OptionalSnippetProperties = {
7
+ prompt?: string;
8
+ showCopyButton?: boolean;
9
+ testId?: string;
10
+ copyIcon?: Snippet;
11
+ classes?: string;
12
+ };
13
+ export type SnippetEventProperties = {
14
+ oncopy?: () => void;
15
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,135 @@
1
+ <script lang="ts">
2
+ import type { SplitButtonProperties } from './properties';
3
+ import type { MenuItem } from '../Menu/properties';
4
+ import Button from '../Button/Button.svelte';
5
+ import Menu from '../Menu/Menu.svelte';
6
+ import chevronDownSmSvg from '../assets/chevron-down-sm.svg?raw';
7
+
8
+ let {
9
+ text,
10
+ items,
11
+ disabled = false,
12
+ testId,
13
+ dropdownIcon,
14
+ classes,
15
+ onclick,
16
+ onselect
17
+ }: SplitButtonProperties = $props();
18
+
19
+ let menuOpen = $state(false);
20
+
21
+ function handlePrimaryClick(event: MouseEvent): void {
22
+ if (disabled) {
23
+ return;
24
+ }
25
+ onclick?.(event);
26
+ }
27
+
28
+ function handleMenuSelect(item: MenuItem): void {
29
+ onselect?.(item);
30
+ }
31
+ </script>
32
+
33
+ <div
34
+ class="split-button {classes ?? ''}"
35
+ class:disabled
36
+ data-pw={typeof testId === 'string' ? testId : null}
37
+ >
38
+ <div class="split-button-primary">
39
+ <Button {text} onclick={handlePrimaryClick} {disabled} />
40
+ </div>
41
+ <div class="split-button-trigger">
42
+ <Menu {items} bind:open={menuOpen} onselect={handleMenuSelect}>
43
+ {#snippet trigger()}
44
+ <span class="split-button-arrow">
45
+ {#if typeof dropdownIcon === 'function'}
46
+ {@render dropdownIcon()}
47
+ {:else}
48
+ <!-- eslint-disable svelte/no-at-html-tags -->
49
+ {@html chevronDownSmSvg}
50
+ {/if}
51
+ </span>
52
+ {/snippet}
53
+ </Menu>
54
+ </div>
55
+ </div>
56
+
57
+ <style>
58
+ .split-button {
59
+ display: inline-flex;
60
+ position: relative;
61
+ gap: var(--split-button-gap, 0px);
62
+ }
63
+
64
+ .split-button.disabled .split-button-trigger {
65
+ pointer-events: none;
66
+ }
67
+
68
+ .split-button-primary {
69
+ --button-color: var(--split-button-primary-background, #3a4550);
70
+ --button-text-color: var(--split-button-primary-color, white);
71
+ --button-padding: var(--split-button-primary-padding, 8px 16px);
72
+ --button-font-size: var(--split-button-primary-font-size, 14px);
73
+ --button-font-weight: var(--split-button-primary-font-weight, 500);
74
+ --button-font-family: var(--split-button-primary-font-family);
75
+ --button-border: var(--split-button-primary-border, none);
76
+ --button-border-radius: var(--split-button-primary-border-radius, 4px 0 0 4px);
77
+ --button-hover-color: var(
78
+ --split-button-primary-hover-background,
79
+ var(--split-button-primary-background, #3a4550)
80
+ );
81
+ --button-hover-text-color: var(
82
+ --split-button-primary-hover-color,
83
+ var(--split-button-primary-color, white)
84
+ );
85
+ --disabled-opacity: var(--split-button-disabled-opacity, 0.4);
86
+ --disabled-cursor: var(--split-button-disabled-cursor, not-allowed);
87
+ display: flex;
88
+ }
89
+
90
+ .split-button-trigger {
91
+ --menu-container-position: static;
92
+ --menu-container-display: flex;
93
+ --menu-trigger-focus-outline: none;
94
+ --menu-dropdown-left: 0;
95
+ --menu-min-width: 100%;
96
+ border-left: var(--split-button-trigger-separator, 1px solid rgba(255, 255, 255, 0.3));
97
+ display: flex;
98
+ align-items: stretch;
99
+ background-color: var(--split-button-trigger-background, #3a4550);
100
+ border-radius: var(--split-button-trigger-border-radius, 0 4px 4px 0);
101
+ color: var(--split-button-trigger-color, white);
102
+ cursor: pointer;
103
+ }
104
+
105
+ .split-button.disabled .split-button-trigger {
106
+ opacity: var(--split-button-disabled-opacity, 0.4);
107
+ cursor: var(--split-button-disabled-cursor, not-allowed);
108
+ }
109
+
110
+ .split-button-trigger:hover {
111
+ background-color: var(
112
+ --split-button-trigger-hover-background,
113
+ var(--split-button-trigger-background, #3a4550)
114
+ );
115
+ color: var(--split-button-trigger-hover-color, var(--split-button-trigger-color, white));
116
+ }
117
+
118
+ .split-button-trigger :global(.menu-trigger) {
119
+ display: flex;
120
+ align-items: center;
121
+ justify-content: center;
122
+ padding: var(--split-button-trigger-padding, 8px);
123
+ }
124
+
125
+ .split-button-arrow {
126
+ display: inline-flex;
127
+ width: var(--split-button-arrow-width, 10px);
128
+ height: var(--split-button-arrow-height, 6px);
129
+ }
130
+
131
+ .split-button-arrow :global(svg) {
132
+ width: 100%;
133
+ height: 100%;
134
+ }
135
+ </style>
@@ -0,0 +1,4 @@
1
+ import type { SplitButtonProperties } from './properties';
2
+ declare const SplitButton: import("svelte").Component<SplitButtonProperties, {}, "">;
3
+ type SplitButton = ReturnType<typeof SplitButton>;
4
+ export default SplitButton;
@@ -0,0 +1,17 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { MenuItem } from '../Menu/properties';
3
+ export type SplitButtonProperties = MandatorySplitButtonProperties & OptionalSplitButtonProperties & SplitButtonEventProperties;
4
+ export type MandatorySplitButtonProperties = {
5
+ text: string;
6
+ items: MenuItem[];
7
+ };
8
+ export type OptionalSplitButtonProperties = {
9
+ disabled?: boolean;
10
+ testId?: string;
11
+ dropdownIcon?: Snippet;
12
+ classes?: string;
13
+ };
14
+ export type SplitButtonEventProperties = {
15
+ onclick?: (event: MouseEvent) => void;
16
+ onselect?: (item: MenuItem) => void;
17
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -1,25 +1,27 @@
1
1
  <script lang="ts">
2
2
  import type { StatusProperties } from './properties';
3
3
  import Button from '../Button/Button.svelte';
4
+ import Img from '../Img/Img.svelte';
4
5
 
5
6
  let {
6
7
  statusIcon = 'icons/order-success-icon.svg',
7
8
  statusText = '',
8
9
  statusDescription = '',
9
10
  buttonProperties,
11
+ classes,
10
12
  onbuttonClick
11
13
  }: StatusProperties = $props();
12
14
  </script>
13
15
 
14
- <div class="background">
16
+ <div class="background {classes ?? ''}">
15
17
  <div class="order-status">
16
- <div class="status-image"><img src={statusIcon} alt="status" /></div>
18
+ <div class="status-image"><Img src={statusIcon} alt="status" /></div>
17
19
  <div class="status-text">{statusText}</div>
18
20
  <div class="status-description">
19
21
  <!-- eslint-disable-next-line -->
20
22
  {@html statusDescription}
21
23
  </div>
22
- {#if buttonProperties}
24
+ {#if typeof buttonProperties === 'object'}
23
25
  <Button {...buttonProperties} onclick={onbuttonClick} />
24
26
  {/if}
25
27
  </div>
@@ -4,6 +4,7 @@ export type StatusProperties = StatusEventProperties & {
4
4
  statusText: string;
5
5
  statusDescription: string;
6
6
  buttonProperties?: ButtonProperties;
7
+ classes?: string;
7
8
  };
8
9
  export type StatusEventProperties = {
9
10
  onbuttonClick?: () => void;
@@ -1,15 +1,15 @@
1
1
  <script lang="ts">
2
2
  import type { StepProperties } from './properties';
3
3
 
4
- let { stepIndex, label, icon, onclick, onkeydown }: StepProperties = $props();
4
+ let { stepIndex, label, icon, classes, onclick, onkeydown }: StepProperties = $props();
5
5
 
6
6
  function handleStepClick() {
7
7
  onclick?.({ selectedIndex: stepIndex });
8
8
  }
9
9
  </script>
10
10
 
11
- <div class="step" onclick={handleStepClick} {onkeydown} role="button" tabindex="0">
12
- {#if icon}
11
+ <div class="step {classes ?? ''}" onclick={handleStepClick} {onkeydown} role="button" tabindex="0">
12
+ {#if typeof icon === 'string' && icon.length > 0}
13
13
  <div class="step-icon-container">
14
14
  <img class="step-icon" src={icon} alt="" />
15
15
  </div>
@@ -2,11 +2,11 @@
2
2
  import type { StepperProperties } from './properties';
3
3
  import Step from './Step.svelte';
4
4
 
5
- let { steps, currentStepIndex, onhandleStepClick }: StepperProperties = $props();
5
+ let { steps, currentStepIndex, classes, onhandleStepClick }: StepperProperties = $props();
6
6
  </script>
7
7
 
8
- <div class="container">
9
- {#each steps as currentStep, stepIndex}
8
+ <div class="container {classes ?? ''}">
9
+ {#each steps as currentStep, stepIndex (stepIndex)}
10
10
  <div
11
11
  class:active-step={currentStepIndex === stepIndex}
12
12
  class:completed-step={currentStepIndex > stepIndex}
@@ -1,6 +1,7 @@
1
1
  export type StepperProperties = {
2
2
  steps: Array<Step>;
3
3
  currentStepIndex: number;
4
+ classes?: string;
4
5
  onhandleStepClick?: (event: {
5
6
  selectedIndex: number;
6
7
  }) => void;
@@ -15,6 +16,7 @@ export type StepProperties = OptionalStepProperties & StepEventProperties & {
15
16
  };
16
17
  export type OptionalStepProperties = {
17
18
  icon?: string;
19
+ classes?: string;
18
20
  };
19
21
  export type StepEventProperties = {
20
22
  onclick?: (event: {
@@ -6,7 +6,8 @@
6
6
  tableHeaders = [],
7
7
  tableData = [],
8
8
  isTableScrollable = false,
9
- isContentScrollable = false
9
+ isContentScrollable = false,
10
+ classes
10
11
  }: TableProperties = $props();
11
12
 
12
13
  let sortOrders = $state<{ [key: string]: 'asc' | 'desc' }>({});
@@ -18,7 +19,10 @@
18
19
  }
19
20
 
20
21
  // Sort by the last clicked column
21
- const column = columns[columns.length - 1];
22
+ const column = columns.at(-1);
23
+ if (!column) {
24
+ return [...tableData];
25
+ }
22
26
  const order = sortOrders[column];
23
27
 
24
28
  return [...tableData].sort((a, b) => {
@@ -49,7 +53,7 @@
49
53
  });
50
54
 
51
55
  function sortTableData(column: string) {
52
- if (!sortOrders[column]) {
56
+ if (typeof sortOrders[column] === 'undefined') {
53
57
  sortOrders[column] = 'asc';
54
58
  } else {
55
59
  sortOrders[column] = sortOrders[column] === 'asc' ? 'desc' : 'asc';
@@ -64,17 +68,20 @@
64
68
  }
65
69
  </script>
66
70
 
67
- {#if tableTitle}
71
+ {#if typeof tableTitle === 'string' && tableTitle.length > 0}
68
72
  <div class="table-title">
69
73
  {tableTitle}
70
74
  </div>
71
75
  {/if}
72
76
  {#if tableHeaders.length !== 0 || tableData.length !== 0}
73
- <div class="table-container {isTableScrollable ? 'scrollable-table' : ' '}" role="grid">
77
+ <div
78
+ class="table-container {isTableScrollable ? 'scrollable-table' : ' '} {classes ?? ''}"
79
+ role="grid"
80
+ >
74
81
  <table>
75
82
  <thead>
76
83
  <tr>
77
- {#each tableHeaders as header}
84
+ {#each tableHeaders as header (header)}
78
85
  <th class="table-header {isTableScrollable ? 'table-header-sticky' : ' '}">
79
86
  {header}
80
87
  {#if sortOrders[header] === 'asc'}
@@ -99,9 +106,9 @@
99
106
  </tr>
100
107
  </thead>
101
108
  <tbody>
102
- {#each sortedTableData as row}
109
+ {#each sortedTableData as row, rowIndex (rowIndex)}
103
110
  <tr>
104
- {#each row as cell}
111
+ {#each row as cell, cellIndex (cellIndex)}
105
112
  <td class="table-content">
106
113
  <div class={isContentScrollable ? 'scrollable-content' : ' '}>
107
114
  {cell}
@@ -5,4 +5,5 @@ export type TableProperties = {
5
5
  tableData?: Array<JSONValue[]>;
6
6
  isTableScrollable?: boolean;
7
7
  isContentScrollable?: boolean;
8
+ classes?: string;
8
9
  };
@@ -0,0 +1,240 @@
1
+ <script lang="ts">
2
+ import type { TabsProperties } from './properties';
3
+ import chevronLeftSvg from '../assets/chevron-left.svg?raw';
4
+ import chevronRightSvg from '../assets/chevron-right.svg?raw';
5
+
6
+ let {
7
+ items,
8
+ activeIndex = 0,
9
+ disabled = false,
10
+ testId,
11
+ scrollLeftIcon,
12
+ scrollRightIcon,
13
+ classes,
14
+ onchange
15
+ }: TabsProperties = $props();
16
+
17
+ let scrollContainer: HTMLDivElement | null = null;
18
+ let canScrollLeft = $state(false);
19
+ let canScrollRight = $state(false);
20
+
21
+ function updateOverflow(): void {
22
+ if (scrollContainer === null) {
23
+ return;
24
+ }
25
+ const { scrollLeft, scrollWidth, clientWidth } = scrollContainer;
26
+ canScrollLeft = scrollLeft > 1;
27
+ canScrollRight = scrollLeft + clientWidth < scrollWidth - 1;
28
+ }
29
+
30
+ function scroll(direction: 'left' | 'right'): void {
31
+ if (scrollContainer === null) {
32
+ return;
33
+ }
34
+ const amount = scrollContainer.clientWidth * 0.6;
35
+ scrollContainer.scrollBy({
36
+ left: direction === 'left' ? -amount : amount,
37
+ behavior: 'smooth'
38
+ });
39
+ }
40
+
41
+ function handleTabClick(index: number): void {
42
+ if (disabled || index === activeIndex) {
43
+ return;
44
+ }
45
+ activeIndex = index;
46
+ onchange?.(index, items[index]);
47
+ }
48
+
49
+ function initOverflow(node: HTMLDivElement): { destroy: () => void } {
50
+ scrollContainer = node;
51
+ updateOverflow();
52
+ const observer = new MutationObserver(updateOverflow);
53
+ observer.observe(node, { childList: true, subtree: true });
54
+ return {
55
+ destroy() {
56
+ observer.disconnect();
57
+ }
58
+ };
59
+ }
60
+ </script>
61
+
62
+ <div class="tabs-wrapper {classes ?? ''}" class:disabled data-pw={testId}>
63
+ {#if canScrollLeft}
64
+ <button
65
+ class="tabs-arrow tabs-arrow-left"
66
+ aria-label="Scroll tabs left"
67
+ onclick={() => scroll('left')}
68
+ >
69
+ {#if typeof scrollLeftIcon === 'function'}
70
+ {@render scrollLeftIcon()}
71
+ {:else}
72
+ <!-- eslint-disable svelte/no-at-html-tags -->
73
+ {@html chevronLeftSvg}
74
+ {/if}
75
+ </button>
76
+ {/if}
77
+ <div
78
+ class="tabs-bar"
79
+ class:fade-left={canScrollLeft}
80
+ class:fade-right={canScrollRight}
81
+ role="tablist"
82
+ use:initOverflow
83
+ onscroll={updateOverflow}
84
+ >
85
+ {#each items as label, index (index)}
86
+ <button
87
+ class="tabs-item"
88
+ class:active={index === activeIndex}
89
+ role="tab"
90
+ aria-selected={index === activeIndex}
91
+ tabindex={index === activeIndex ? 0 : -1}
92
+ {disabled}
93
+ onclick={() => handleTabClick(index)}
94
+ >
95
+ {label}
96
+ {#if index === activeIndex}
97
+ <span class="tabs-indicator"></span>
98
+ {/if}
99
+ </button>
100
+ {/each}
101
+ </div>
102
+ {#if canScrollRight}
103
+ <button
104
+ class="tabs-arrow tabs-arrow-right"
105
+ aria-label="Scroll tabs right"
106
+ onclick={() => scroll('right')}
107
+ >
108
+ {#if typeof scrollRightIcon === 'function'}
109
+ {@render scrollRightIcon()}
110
+ {:else}
111
+ <!-- eslint-disable svelte/no-at-html-tags -->
112
+ {@html chevronRightSvg}
113
+ {/if}
114
+ </button>
115
+ {/if}
116
+ </div>
117
+
118
+ <style>
119
+ .tabs-wrapper {
120
+ display: flex;
121
+ align-items: stretch;
122
+ position: relative;
123
+ max-width: 100%;
124
+ background: var(--tabs-bar-background, #ffffff);
125
+ border-bottom: var(--tabs-bar-border-bottom, 1px solid #e0e0e0);
126
+ border-radius: var(--tabs-bar-border-radius, 0);
127
+ }
128
+
129
+ .tabs-wrapper.disabled {
130
+ opacity: var(--tabs-disabled-opacity, 0.5);
131
+ pointer-events: none;
132
+ }
133
+
134
+ .tabs-bar {
135
+ display: flex;
136
+ flex: 1;
137
+ min-width: 0;
138
+ padding: var(--tabs-bar-padding, 0px);
139
+ gap: var(--tabs-bar-gap, 0px);
140
+ overflow-x: auto;
141
+ scrollbar-width: none;
142
+ }
143
+
144
+ .tabs-bar::-webkit-scrollbar {
145
+ display: none;
146
+ }
147
+
148
+ .tabs-bar.fade-left {
149
+ mask-image: linear-gradient(to right, transparent, black var(--tabs-fade-size, 32px));
150
+ -webkit-mask-image: linear-gradient(to right, transparent, black var(--tabs-fade-size, 32px));
151
+ }
152
+
153
+ .tabs-bar.fade-right {
154
+ mask-image: linear-gradient(to left, transparent, black var(--tabs-fade-size, 32px));
155
+ -webkit-mask-image: linear-gradient(to left, transparent, black var(--tabs-fade-size, 32px));
156
+ }
157
+
158
+ .tabs-bar.fade-left.fade-right {
159
+ mask-image: linear-gradient(
160
+ to right,
161
+ transparent,
162
+ black var(--tabs-fade-size, 32px),
163
+ black calc(100% - var(--tabs-fade-size, 32px)),
164
+ transparent
165
+ );
166
+ -webkit-mask-image: linear-gradient(
167
+ to right,
168
+ transparent,
169
+ black var(--tabs-fade-size, 32px),
170
+ black calc(100% - var(--tabs-fade-size, 32px)),
171
+ transparent
172
+ );
173
+ }
174
+
175
+ .tabs-arrow {
176
+ display: flex;
177
+ align-items: center;
178
+ justify-content: center;
179
+ flex-shrink: 0;
180
+ width: var(--tabs-arrow-size, 28px);
181
+ padding: var(--tabs-arrow-padding, 0);
182
+ border: var(--tabs-arrow-border, none);
183
+ background: var(--tabs-arrow-background, var(--tabs-bar-background, #ffffff));
184
+ color: var(--tabs-arrow-color, var(--tabs-item-color, #666666));
185
+ cursor: pointer;
186
+ z-index: 1;
187
+ transition: var(--tabs-arrow-transition, color 0.2s ease);
188
+ font-family: inherit;
189
+ }
190
+
191
+ .tabs-arrow:hover {
192
+ color: var(--tabs-arrow-hover-color, var(--tabs-active-color, #1a73e8));
193
+ background: var(
194
+ --tabs-arrow-hover-background,
195
+ var(--tabs-arrow-background, var(--tabs-bar-background, #ffffff))
196
+ );
197
+ }
198
+
199
+ .tabs-item {
200
+ position: relative;
201
+ padding: var(--tabs-item-padding, 12px 16px);
202
+ font-size: var(--tabs-item-font-size, 14px);
203
+ font-weight: var(--tabs-item-font-weight, 400);
204
+ font-family: var(--tabs-item-font-family, inherit);
205
+ color: var(--tabs-item-color, #666666);
206
+ cursor: var(--tabs-item-cursor, pointer);
207
+ background: var(--tabs-item-background, transparent);
208
+ border: none;
209
+ border-radius: var(--tabs-item-border-radius, 0);
210
+ outline: none;
211
+ white-space: nowrap;
212
+ flex-shrink: 0;
213
+ transition: var(--tabs-transition, color 0.2s ease, background 0.2s ease);
214
+ }
215
+
216
+ .tabs-item:hover:not(.active):not(:disabled) {
217
+ color: var(--tabs-hover-color, #333333);
218
+ background: var(--tabs-hover-background, #f5f5f5);
219
+ }
220
+
221
+ .tabs-item.active {
222
+ color: var(--tabs-active-color, #1a73e8);
223
+ font-weight: var(--tabs-active-font-weight, 600);
224
+ background: var(--tabs-active-background, transparent);
225
+ }
226
+
227
+ .tabs-item:disabled {
228
+ cursor: var(--tabs-disabled-cursor, not-allowed);
229
+ }
230
+
231
+ .tabs-indicator {
232
+ position: absolute;
233
+ bottom: 0;
234
+ left: 0;
235
+ right: 0;
236
+ height: var(--tabs-indicator-height, 2px);
237
+ background-color: var(--tabs-indicator-color, #1a73e8);
238
+ border-radius: var(--tabs-indicator-border-radius, 2px 2px 0 0);
239
+ }
240
+ </style>
@@ -0,0 +1,4 @@
1
+ import type { TabsProperties } from './properties';
2
+ declare const Tabs: import("svelte").Component<TabsProperties, {}, "">;
3
+ type Tabs = ReturnType<typeof Tabs>;
4
+ export default Tabs;
@@ -0,0 +1,16 @@
1
+ import type { Snippet } from 'svelte';
2
+ export type TabsProperties = MandatoryTabsProperties & OptionalTabsProperties & TabsEventProperties;
3
+ export type MandatoryTabsProperties = {
4
+ items: string[];
5
+ };
6
+ export type OptionalTabsProperties = {
7
+ activeIndex?: number;
8
+ disabled?: boolean;
9
+ testId?: string;
10
+ scrollLeftIcon?: Snippet;
11
+ scrollRightIcon?: Snippet;
12
+ classes?: string;
13
+ };
14
+ export type TabsEventProperties = {
15
+ onchange?: (index: number, label: string) => void;
16
+ };
@@ -0,0 +1 @@
1
+ export {};