@coyalabs/bts-style 1.3.10 → 1.3.11

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 (38) hide show
  1. package/README.md +193 -5
  2. package/dist/Base/BaseContainer.svelte +10 -2
  3. package/dist/Base/BasePage.svelte +1 -6
  4. package/dist/Base/BasePage.svelte.d.ts +0 -3
  5. package/dist/Base/BaseText.svelte +19 -6
  6. package/dist/Base/BaseText.svelte.d.ts +4 -2
  7. package/dist/Base/variantTypes.d.ts +3 -2
  8. package/dist/Base/variantTypes.js +3 -1
  9. package/dist/Components/Button.svelte +78 -17
  10. package/dist/Components/Button.svelte.d.ts +8 -0
  11. package/dist/Components/CodeBlock.svelte +167 -0
  12. package/dist/Components/CodeBlock.svelte.d.ts +40 -0
  13. package/dist/Components/ContextMenu.svelte +120 -31
  14. package/dist/Components/ContextMenu.svelte.d.ts +2 -0
  15. package/dist/Components/Dropdown.svelte +2 -2
  16. package/dist/Components/InputBox.svelte +3 -3
  17. package/dist/Components/LinearList.svelte +7 -2
  18. package/dist/Components/LoadingSpinner.svelte +58 -0
  19. package/dist/Components/LoadingSpinner.svelte.d.ts +30 -0
  20. package/dist/Components/Popup/Popup.svelte +1 -1
  21. package/dist/Components/ScrollContainer.svelte +95 -0
  22. package/dist/Components/ScrollContainer.svelte.d.ts +59 -0
  23. package/dist/Components/Special/SpecialAction.svelte +11 -13
  24. package/dist/Components/Special/SpecialAction.svelte.d.ts +2 -0
  25. package/dist/Components/TabBar.svelte +4 -3
  26. package/dist/Components/TabBar.svelte.d.ts +10 -2
  27. package/dist/Components/Toast/Toast.svelte +36 -11
  28. package/dist/Components/Toast/Toast.svelte.d.ts +6 -0
  29. package/dist/Components/Toggle.svelte +3 -3
  30. package/dist/Components/TreeDirectory.svelte +28 -10
  31. package/dist/Components/TreeDirectory.svelte.d.ts +36 -4
  32. package/dist/Structure/TextHeader.svelte +33 -4
  33. package/dist/Structure/TextHeader.svelte.d.ts +6 -0
  34. package/dist/icons.d.ts +8 -0
  35. package/dist/icons.js +11 -3
  36. package/dist/index.d.ts +3 -0
  37. package/dist/index.js +3 -0
  38. package/package.json +2 -2
package/README.md CHANGED
@@ -192,6 +192,9 @@ Clickable button extending BaseContainer with icon support.
192
192
  - `actionIconRotation?: number` - Right icon rotation in degrees
193
193
  - `iconSize?: string` - Left icon size (default: `'18px'`)
194
194
  - `actionIconSize?: string` - Right icon size (default: `'18px'`)
195
+ - `disabled?: boolean` - Disable interaction (default: `false`)
196
+ - `loading?: boolean` - Show loading spinner, hide content, and disable button (default: `false`)
197
+ - `loadingSize?: string` - Spinner size when loading (default: `'18px'`)
195
198
  - All BaseContainer corner radius props
196
199
 
197
200
  **Events:**
@@ -201,6 +204,13 @@ Clickable button extending BaseContainer with icon support.
201
204
  ```svelte
202
205
  <script>
203
206
  import { Button, icons } from '@coyalabs/bts-style';
207
+ let isLoading = false;
208
+
209
+ async function handleClick() {
210
+ isLoading = true;
211
+ await someAsyncOperation();
212
+ isLoading = false;
213
+ }
204
214
  </script>
205
215
 
206
216
  <Button
@@ -216,11 +226,23 @@ Clickable button extending BaseContainer with icon support.
216
226
  <Button actionIcon={null} theme="secondary">
217
227
  Simple Button
218
228
  </Button>
229
+
230
+ <!-- Loading state -->
231
+ <Button loading={isLoading} on:click={handleClick}>
232
+ Submit Form
233
+ </Button>
234
+
235
+ <!-- Disabled state -->
236
+ <Button disabled theme="secondary">
237
+ Disabled Button
238
+ </Button>
219
239
  ```
220
240
 
221
241
  **States:**
222
242
  - Hover: Subtle background lightening
223
243
  - Active/Pressed: Visual feedback
244
+ - Disabled: Non-interactive, reduced opacity, `not-allowed` cursor
245
+ - Loading: Shows spinner, disables interaction (opacity 0.7)
224
246
 
225
247
  ---
226
248
 
@@ -255,6 +277,45 @@ Circular icon-only button with hover effects.
255
277
 
256
278
  ---
257
279
 
280
+ #### LoadingSpinner
281
+
282
+ Animated loading spinner using the light gear from the BTS theme assets. Insertable into any component (buttons, containers, inline text, etc.).
283
+
284
+ **Props:**
285
+ - `size?: string` - Spinner size (default: `'20px'`)
286
+ - `speed?: number` - Rotation speed in seconds (default: `2`)
287
+ - `color?: string | null` - Custom color (default: `'white'`)
288
+
289
+ **Example:**
290
+ ```svelte
291
+ <script>
292
+ import { LoadingSpinner } from '@coyalabs/bts-style';
293
+ </script>
294
+
295
+ <!-- Basic usage -->
296
+ <LoadingSpinner />
297
+
298
+ <!-- Custom size and speed -->
299
+ <LoadingSpinner size="40px" speed={1.5} />
300
+
301
+ <!-- Inside a button -->
302
+ <Button theme="primary">
303
+ Loading <LoadingSpinner size="16px" />
304
+ </Button>
305
+
306
+ <!-- Custom color -->
307
+ <LoadingSpinner size="2rem" color="#FFEFF6" />
308
+ ```
309
+
310
+ **Features:**
311
+ - Smooth infinite rotation animation
312
+ - Uses `inline-flex` display for easy insertion anywhere
313
+ - Defaults to `currentColor` to inherit parent text color
314
+ - Configurable rotation speed
315
+ - Based on the light gear asset from assetGear.js
316
+
317
+ ---
318
+
258
319
  #### InputBox
259
320
 
260
321
  Text input field with icon support and theme matching.
@@ -282,6 +343,96 @@ Text input field with icon support and theme matching.
282
343
  />
283
344
  ```
284
345
 
346
+ ---
347
+
348
+ #### CodeBlock
349
+
350
+ Code display component with syntax highlighting-ready styling and copy-to-clipboard functionality.
351
+
352
+ **Props:**
353
+ - `code: string` - Code content to display
354
+ - `language?: string` - Optional language label (e.g., `'javascript'`, `'python'`)
355
+ - `theme?: 'full' | 'primary' | 'secondary' | 'filled'` - Visual theme (default: `'secondary'`)
356
+ - `showCopy?: boolean` - Show copy button (default: `true`)
357
+ - All BaseContainer corner radius props
358
+
359
+ **Example:**
360
+ ```svelte
361
+ <script>
362
+ import { CodeBlock } from '@coyalabs/bts-style';
363
+
364
+ const myCode = `function hello() {
365
+ console.log('Hello, world!');
366
+ }`;
367
+ </script>
368
+
369
+ <CodeBlock
370
+ code={myCode}
371
+ language="javascript"
372
+ theme="secondary"
373
+ />
374
+
375
+ <!-- Without language label -->
376
+ <CodeBlock
377
+ code="npm install @coyalabs/bts-style"
378
+ showCopy={true}
379
+ />
380
+ ```
381
+
382
+ **Features:**
383
+ - Monospace font display (`Courier New`)
384
+ - Horizontal scrolling for long lines
385
+ - Copy button with visual feedback (check icon for 2 seconds)
386
+ - Optional language label in header
387
+ - Styled scrollbar matching theme
388
+ - Preserves whitespace and formatting
389
+
390
+ **Visual Design:**
391
+ - Code displayed in `#E3D8D8` color
392
+ - Language label in toned color (`#A18F8F`)
393
+ - Custom scrollbar with theme colors
394
+ - Copy button uses IconButton with toned variant
395
+ - Header with language and copy button (if enabled)
396
+
397
+
398
+ ---
399
+
400
+ #### ScrollContainer
401
+
402
+ Reusable overflow wrapper with theme-matching custom scrollbar styling.
403
+
404
+ **Props:**
405
+ - `overflowX?: 'auto' | 'scroll' | 'hidden' | 'visible'` - Horizontal overflow mode (default: `'auto'`)
406
+ - `overflowY?: 'auto' | 'scroll' | 'hidden' | 'visible'` - Vertical overflow mode (default: `'auto'`)
407
+ - `width?: string` - Container width (default: `'100%'`)
408
+ - `height?: string` - Container height (default: `'auto'`)
409
+ - `maxWidth?: string` - Max width (default: `'100%'`)
410
+ - `maxHeight?: string` - Max height (default: `'none'`)
411
+ - `scrollbarSize?: string` - Scrollbar thickness/height (default: `'8px'`)
412
+ - `trackColor?: string` - Scrollbar track color (default: `'rgba(161, 143, 143, 0.1)'`)
413
+ - `thumbColor?: string` - Scrollbar thumb color (default: `'rgba(161, 143, 143, 0.3)'`)
414
+ - `thumbHoverColor?: string` - Scrollbar thumb hover color (default: `'rgba(161, 143, 143, 0.5)'`)
415
+ - `borderRadius?: string` - Scrollbar track/thumb radius (default: `'4px'`)
416
+
417
+ **Example:**
418
+ ```svelte
419
+ <script>
420
+ import { ScrollContainer } from '@coyalabs/bts-style';
421
+ </script>
422
+
423
+ <ScrollContainer overflowY="auto" maxHeight="320px">
424
+ <div style="min-height: 640px;">
425
+ Scrollable content with BTS-themed scrollbar.
426
+ </div>
427
+ </ScrollContainer>
428
+ ```
429
+
430
+ **Features:**
431
+ - Reusable themed scrollbar styles from a single component
432
+ - Supports both horizontal and vertical overflow use cases
433
+ - Works with slot content (lists, code areas, panels, etc.)
434
+ - Includes Firefox `scrollbar-color`/`scrollbar-width` support
435
+
285
436
 
286
437
  ---
287
438
 
@@ -344,13 +495,19 @@ Vertical tab navigation with support for categorized groups.
344
495
  **TabItem Type:**
345
496
  ```typescript
346
497
  type TabItem = {
347
- id?: string; // Required for tabs, omit for separators
348
- label: string; // Tab/separator text
349
- icon?: string; // Optional icon SVG
498
+ id?: string; // Required for tabs, omit for separators
499
+ label: string; // Tab/separator text
350
500
  type?: 'tab' | 'separator'; // Default: 'tab'
501
+ // Icon props (spread directly onto Button):
502
+ icon?: string; // Icon SVG markup
503
+ iconRotation?: number; // Icon rotation in degrees
504
+ iconSize?: string; // Icon size (default: '18px')
505
+ iconToned?: boolean; // Use toned icon variant
351
506
  }
352
507
  ```
353
508
 
509
+ Any extra properties on a tab item beyond `id`, `label`, and `type` are forwarded directly to the underlying `Button` component as props. This means all Button icon-related props (`icon`, `iconRotation`, `iconSize`, `iconToned`) can be set per-tab without needing to be individually declared.
510
+
354
511
  **Example:**
355
512
  ```svelte
356
513
  <script>
@@ -408,11 +565,12 @@ Expandable file/folder tree with recursive structure.
408
565
  ```typescript
409
566
  type TreeItem = {
410
567
  name: string;
411
- type: 'file' | 'folder';
568
+ type: 'file' | 'folder' | 'custom';
412
569
  children?: TreeItem[];
413
570
  data?: any; // Custom data attached to item
414
571
  variant?: 'full' | 'primary' | 'secondary' | 'filled' | 'special-filled'; // Theme variant
415
572
  suffixIcon?: string; // SVG icon displayed on the right
573
+ isPending?: boolean; // Show pending state with reduced opacity
416
574
  }
417
575
  ```
418
576
 
@@ -550,6 +708,24 @@ Display additional icons on the right side of items:
550
708
  }
551
709
  ```
552
710
 
711
+ **Custom Items:**
712
+ Use `type: 'custom'` to render custom components via slot:
713
+ ```svelte
714
+ <TreeDirectory items={[
715
+ { name: 'folder', type: 'folder', children: [...] },
716
+ { name: 'custom-widget', type: 'custom', data: {...} }
717
+ ]}>
718
+ <svelte:fragment slot="custom" let:item let:isNested let:isLast>
719
+ <YourCustomComponent {item} {isNested} {isLast} />
720
+ </svelte:fragment>
721
+ </TreeDirectory>
722
+ ```
723
+
724
+ **Corner Radius Behavior:**
725
+ - Custom items act as list terminators for corner radius calculations
726
+ - If the next item is of `type: 'custom'`, the current item's bottom corners will be fully rounded (25px)
727
+ - This creates visual separation between standard tree items and custom slot components
728
+
553
729
  ---
554
730
 
555
731
  ### Popup System
@@ -938,6 +1114,7 @@ A special-themed button with gradient background and optional tooltip.
938
1114
  **Props:**
939
1115
  - `label: string` - Button text
940
1116
  - `tooltipText?: string` - Optional tooltip text displayed on the right
1117
+ - All Button corner radius props (`borderRadiusTopLeft`, `borderRadiusTopRight`, `borderRadiusBottomLeft`, `borderRadiusBottomRight`)
941
1118
 
942
1119
  **Example:**
943
1120
  ```svelte
@@ -949,6 +1126,13 @@ A special-themed button with gradient background and optional tooltip.
949
1126
  label="AI Generate"
950
1127
  tooltipText="Uses AI to generate content"
951
1128
  />
1129
+
1130
+ <!-- With custom corners -->
1131
+ <SpecialAction
1132
+ label="AI Generate"
1133
+ borderRadiusTopLeft="35px"
1134
+ borderRadiusBottomRight="35px"
1135
+ />
952
1136
  ```
953
1137
 
954
1138
  **Features:**
@@ -1028,12 +1212,13 @@ Animated text component that reveals words sequentially with fade and blur effec
1028
1212
 
1029
1213
  #### ContextMenu
1030
1214
 
1031
- Categorized menu component with separator support, similar to TabBar layout.
1215
+ Categorized menu component with separator support and animated scale-in from a specified corner.
1032
1216
 
1033
1217
  **Props:**
1034
1218
  - `items: Array<ContextMenuItem>` - Array of menu items and separators
1035
1219
  - `selectedValue?: any` - Currently selected item value
1036
1220
  - `onSelect?: (value: any) => void` - Callback when item is selected
1221
+ - `origin?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'` - Animation origin corner (default: `'top-left'`)
1037
1222
 
1038
1223
  **ContextMenuItem Type:**
1039
1224
  ```typescript
@@ -1066,6 +1251,7 @@ type ContextMenuItem = {
1066
1251
  <ContextMenu
1067
1252
  items={menuItems}
1068
1253
  {selectedValue}
1254
+ origin="bottom-right"
1069
1255
  onSelect={(val) => handleAction(val)}
1070
1256
  />
1071
1257
  ```
@@ -1078,6 +1264,8 @@ type ContextMenuItem = {
1078
1264
  - Filled theme container
1079
1265
  - Automatic category spacing and borders
1080
1266
  - Text ellipsis for long labels
1267
+ - Smooth scale-in animation from specified corner (350ms with backOut easing)
1268
+ - Scale-out animation on dismiss (200ms)
1081
1269
 
1082
1270
  **Visual Layout:**
1083
1271
  - Categories separated by labeled dividers
@@ -42,10 +42,10 @@
42
42
 
43
43
  <style>
44
44
  .glow-base-container {
45
- width: 100%;
46
45
  border: 2px solid rgba(255, 255, 255, 0.13);
47
46
  padding: var(--padding);
48
47
  box-sizing: border-box;
48
+ height: 100%;
49
49
  }
50
50
 
51
51
  /* Theme A - Full */
@@ -79,6 +79,14 @@
79
79
  inset 0px 0px 9px 2px #66588048;
80
80
  }
81
81
 
82
+ .glow-base-container[data-theme='error'] {
83
+ background: #331e1e;
84
+ border: 3px solid #563737;
85
+ box-shadow:
86
+ 0px 0px 13px 0px rgba(255, 255, 255, 0.07),
87
+ inset 0px 0px 9px 2px #5c4b4b48;
88
+ }
89
+
82
90
  /* Theme D - Filled */
83
91
  .glow-base-container[data-theme='filled'] {
84
92
  background: #161319;
@@ -87,7 +95,7 @@
87
95
  inset 0px 0px 9px 2px #ffffff0a;
88
96
  }
89
97
 
90
- /* Theme D - Filled */
98
+ /* Theme F - Special Filled */
91
99
  .glow-base-container[data-theme='special-filled'] {
92
100
  background: linear-gradient(-78deg, #382D40 0%, #3A2B45 100%);
93
101
  box-shadow:
@@ -12,11 +12,6 @@
12
12
  */
13
13
  export let showBGDetails = true;
14
14
 
15
- /**
16
- * @type {string}
17
- */
18
- export let chainColor = "#130F15";
19
-
20
15
  onMount(() => {
21
16
  // Set favicon if not already set
22
17
  let link = document.querySelector("link[rel*='icon']") as HTMLLinkElement | null;
@@ -36,7 +31,7 @@
36
31
 
37
32
  <div class="base-page">
38
33
  {#if showBGDetails}
39
- <BGDetails {chainColor} />
34
+ <BGDetails />
40
35
  {/if}
41
36
  <div class="page-content">
42
37
  <slot />
@@ -23,9 +23,6 @@ declare const BasePage: $$__sveltets_2_IsomorphicComponent<$$__sveltets_2_PropsW
23
23
  /**
24
24
  * @type {boolean}
25
25
  */ showBGDetails?: boolean;
26
- /**
27
- * @type {string}
28
- */ chainColor?: string;
29
26
  }, {
30
27
  default: {};
31
28
  }>, {
@@ -1,45 +1,58 @@
1
1
  <script>
2
2
  /**
3
- * @type {'title' | 'content' | 'button'}
3
+ * @type {'title' | 'content' | 'button' | 'code'}
4
4
  */
5
5
  export let variant = 'content';
6
6
  /**
7
7
  * @type {string}
8
8
  */
9
9
  export let textModifier = '0px';
10
+
11
+ /**
12
+ * @type {string}
13
+ */
14
+ export let textWeightModifier = '0';
10
15
  </script>
11
16
 
12
- <span class="text" data-variant={variant} style="--text-modifier: {textModifier};">
17
+ <span class="text" data-variant={variant} style="--text-modifier: {textModifier}; --text-weight-modifier: {textWeightModifier};">
13
18
  <slot />
14
19
  </span>
15
20
 
16
21
  <style>
17
- @import url('https://fonts.googleapis.com/css2?family=Noto+Serif+KR:wght@900&display=swap');
22
+ @import url('https://fonts.googleapis.com/css2?family=Noto+Serif+KR:wght@200..900&display=swap');
18
23
  @import url('https://api.fontshare.com/v2/css?f[]=satoshi@400,500,700,900&display=swap');
24
+ @import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:ital,wght@0,100..800;1,100..800&display=swap');
19
25
  .text {
20
26
  display: inline-flex;
21
27
  align-items: center;
22
28
  font-family: 'Satoshi', sans-serif;
29
+ caret-color: #544a51;
23
30
  }
24
31
  /* Title variant */
25
32
  .text[data-variant='title'] {
26
33
  font-family: 'Noto Serif KR', serif;
27
- font-weight: 900;
34
+ font-weight: calc(900 + var(--text-weight-modifier));
28
35
  font-size: calc(30px + var(--text-modifier));
29
36
  color: #E3D8D8;
30
37
  }
31
38
  /* Content variant */
32
39
  .text[data-variant='content'] {
33
40
  font-family: 'Satoshi', sans-serif;
34
- font-weight: 700;
41
+ font-weight: calc(700 + var(--text-weight-modifier));
35
42
  font-size: calc(18px + var(--text-modifier));
36
43
  color: #777073;
37
44
  }
38
45
  /* Button variant */
39
46
  .text[data-variant='button'] {
40
47
  font-family: 'Noto Serif KR', serif;
41
- font-weight: 900;
48
+ font-weight: calc(600 + var(--text-weight-modifier));
42
49
  font-size: calc(17px + var(--text-modifier));
43
50
  color: #E3D8D8;
44
51
  }
52
+ /* Code variant */
53
+ .text[data-variant='code'] {
54
+ font-family: 'JetBrains Mono', monospace;
55
+ font-size: calc(14px + var(--text-modifier));
56
+ color: #E3D8D8;
57
+ }
45
58
  </style>
@@ -1,7 +1,8 @@
1
1
  export default BaseText;
2
2
  type BaseText = SvelteComponent<$$__sveltets_2_PropsWithChildren<{
3
- variant?: "button" | "title" | "content" | undefined;
3
+ variant?: "button" | "code" | "title" | "content" | undefined;
4
4
  textModifier?: string | undefined;
5
+ textWeightModifier?: string | undefined;
5
6
  }, {
6
7
  default: {};
7
8
  }>, {
@@ -12,8 +13,9 @@ type BaseText = SvelteComponent<$$__sveltets_2_PropsWithChildren<{
12
13
  $$bindings?: string | undefined;
13
14
  };
14
15
  declare const BaseText: $$__sveltets_2_IsomorphicComponent<$$__sveltets_2_PropsWithChildren<{
15
- variant?: "button" | "title" | "content" | undefined;
16
+ variant?: "button" | "code" | "title" | "content" | undefined;
16
17
  textModifier?: string | undefined;
18
+ textWeightModifier?: string | undefined;
17
19
  }, {
18
20
  default: {};
19
21
  }>, {
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @typedef {'full' | 'primary' | 'secondary' | 'filled' | 'special-filled'} BaseContainerVariant
2
+ * @typedef {'full' | 'primary' | 'secondary' | 'error' | 'vague' | 'filled' | 'special-filled'} BaseContainerVariant
3
3
  */
4
4
  /**
5
5
  * Default variant values as constants
@@ -7,7 +7,8 @@
7
7
  export const VARIANT_FULL: "full";
8
8
  export const VARIANT_PRIMARY: "primary";
9
9
  export const VARIANT_SECONDARY: "secondary";
10
+ export const VARIANT_ERROR: "error";
10
11
  export const VARIANT_VAGUE: "vague";
11
12
  export const VARIANT_FILLED: "filled";
12
13
  export const VARIANT_SPECIAL_FILLED: "special-filled";
13
- export type BaseContainerVariant = "full" | "primary" | "secondary" | "filled" | "special-filled";
14
+ export type BaseContainerVariant = "full" | "primary" | "secondary" | "error" | "vague" | "filled" | "special-filled";
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @typedef {'full' | 'primary' | 'secondary' | 'filled' | 'special-filled'} BaseContainerVariant
2
+ * @typedef {'full' | 'primary' | 'secondary' | 'error' | 'vague' | 'filled' | 'special-filled'} BaseContainerVariant
3
3
  */
4
4
 
5
5
  /**
@@ -8,6 +8,8 @@
8
8
  export const VARIANT_FULL = /** @type {const} */ ('full');
9
9
  export const VARIANT_PRIMARY = /** @type {const} */ ('primary');
10
10
  export const VARIANT_SECONDARY = /** @type {const} */ ('secondary');
11
+ export const VARIANT_ERROR = /** @type {const} */ ('error');
12
+
11
13
  export const VARIANT_VAGUE = /** @type {const} */ ('vague');
12
14
  export const VARIANT_FILLED = /** @type {const} */ ('filled');
13
15
  export const VARIANT_SPECIAL_FILLED = /** @type {const} */ ('special-filled');
@@ -2,6 +2,7 @@
2
2
  import BaseContainer from '../Base/BaseContainer.svelte';
3
3
  import BaseText from '../Base/BaseText.svelte';
4
4
  import BaseIcon from '../Base/BaseIcon.svelte';
5
+ import LoadingSpinner from './LoadingSpinner.svelte';
5
6
  import { icons } from '../icons';
6
7
  import { VARIANT_FULL } from '../Base/variantTypes.js';
7
8
 
@@ -73,30 +74,59 @@
73
74
  * @type {string}
74
75
  */
75
76
  export let borderRadiusBottomRight = '25px';
77
+
78
+ /**
79
+ * @type {boolean}
80
+ */
81
+ export let loading = false;
82
+
83
+ /**
84
+ * @type {boolean}
85
+ */
86
+ export let disabled = false;
87
+
88
+ /**
89
+ * @type {string}
90
+ */
91
+ export let loadingSize = '18px';
92
+
93
+ /**
94
+ * @type {boolean}
95
+ */
96
+ export let hideLabel = false;
76
97
  </script>
77
98
 
78
- <button class="button-wrapper" on:click>
99
+ <button class="button-wrapper" on:click disabled={loading || disabled}>
79
100
  <BaseContainer {theme} {borderRadiusTopLeft} {borderRadiusTopRight} {borderRadiusBottomLeft} {borderRadiusBottomRight}>
80
101
  <div class="button-content">
81
- {#if icon || $$slots.default}
82
- <div class="icon-text">
83
- {#if icon}
84
- <div class="icon-wrapper" style="transform: rotate({iconRotation}deg)">
85
- <BaseIcon variant={iconToned ? "toned" : "default"} svg={icon} size={iconSize} />
86
- </div>
87
- {/if}
88
- {#if $$slots.default}
89
- <div style="transform: translateY({correctTextOffset ? '-2px' : '0px'})">
90
- <BaseText variant="button">
91
- <slot />
92
- </BaseText>
102
+ <div class="button-inner" class:loading>
103
+ <div class="left-content">
104
+ {#if icon || ($$slots.default && !hideLabel)}
105
+ <div class="icon-text">
106
+ {#if icon}
107
+ <div class="icon-wrapper" style="transform: rotate({iconRotation}deg)">
108
+ <BaseIcon variant={iconToned ? "toned" : "default"} svg={icon} size={iconSize} />
109
+ </div>
110
+ {/if}
111
+ {#if $$slots.default && !hideLabel}
112
+ <div style="transform: translateY({correctTextOffset ? '-2px' : '0px'})">
113
+ <BaseText variant="button">
114
+ <slot />
115
+ </BaseText>
116
+ </div>
117
+ {/if}
93
118
  </div>
94
119
  {/if}
95
120
  </div>
96
- {/if}
97
- {#if actionIcon}
98
- <div class="icon-wrapper" style="transform: rotate({actionIconRotation}deg)">
99
- <BaseIcon svg={actionIcon} size={actionIconSize} />
121
+ {#if actionIcon}
122
+ <div class="icon-wrapper" style="transform: rotate({actionIconRotation}deg)">
123
+ <BaseIcon svg={actionIcon} size={actionIconSize} />
124
+ </div>
125
+ {/if}
126
+ </div>
127
+ {#if loading}
128
+ <div class="loading-wrapper">
129
+ <LoadingSpinner size={loadingSize} />
100
130
  </div>
101
131
  {/if}
102
132
  </div>
@@ -109,15 +139,46 @@
109
139
  cursor: pointer;
110
140
  display: block;
111
141
  width: 100%;
142
+ height: 60px;
112
143
  user-select: none;
113
144
  overflow: visible;
114
145
  }
115
146
 
147
+ .button-wrapper:disabled {
148
+ opacity: 0.7;
149
+ pointer-events: none;
150
+ filter: saturate(0%);
151
+ }
152
+
116
153
  .button-content {
154
+ position: relative;
155
+ width: 100%;
156
+ height: 100%;
157
+ display: flex;
158
+ align-items: center;
159
+ }
160
+
161
+ .button-inner {
117
162
  display: flex;
163
+ width: 100%;
118
164
  align-items: center;
119
165
  justify-content: space-between;
120
166
  gap: 25px;
167
+ transition: opacity 0.2s ease;
168
+ }
169
+
170
+ .button-inner.loading {
171
+ opacity: 0;
172
+ }
173
+
174
+ .loading-wrapper {
175
+ position: absolute;
176
+ top: 50%;
177
+ left: 50%;
178
+ transform: translate(-50%, -50%);
179
+ display: flex;
180
+ justify-content: center;
181
+ align-items: center;
121
182
  }
122
183
 
123
184
  .icon-text {
@@ -13,6 +13,10 @@ type Button = SvelteComponent<$$__sveltets_2_PropsWithChildren<{
13
13
  iconSize?: string | undefined;
14
14
  iconToned?: boolean | undefined;
15
15
  actionIconSize?: string | undefined;
16
+ loading?: boolean | undefined;
17
+ disabled?: boolean | undefined;
18
+ loadingSize?: string | undefined;
19
+ hideLabel?: boolean | undefined;
16
20
  }, {
17
21
  default: {};
18
22
  }>, {
@@ -38,6 +42,10 @@ declare const Button: $$__sveltets_2_IsomorphicComponent<$$__sveltets_2_PropsWit
38
42
  iconSize?: string | undefined;
39
43
  iconToned?: boolean | undefined;
40
44
  actionIconSize?: string | undefined;
45
+ loading?: boolean | undefined;
46
+ disabled?: boolean | undefined;
47
+ loadingSize?: string | undefined;
48
+ hideLabel?: boolean | undefined;
41
49
  }, {
42
50
  default: {};
43
51
  }>, {