@softwareone/spi-sv5-library 1.0.0 → 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 (60) hide show
  1. package/README.md +75 -19
  2. package/dist/Accordion/Accordion.svelte +89 -0
  3. package/dist/Accordion/Accordion.svelte.d.ts +9 -0
  4. package/dist/Button/Button.svelte +12 -1
  5. package/dist/Button/Button.svelte.d.ts +1 -1
  6. package/dist/Card/Card.svelte +2 -16
  7. package/dist/Card/Card.svelte.d.ts +0 -1
  8. package/dist/Chips/Chips.svelte +31 -34
  9. package/dist/Chips/Chips.svelte.d.ts +1 -1
  10. package/dist/ErrorPage/ErrorPage.svelte +6 -7
  11. package/dist/ErrorPage/ErrorPage.svelte.d.ts +1 -2
  12. package/dist/Form/Input/Input.svelte +16 -43
  13. package/dist/Form/Input/Input.svelte.d.ts +3 -2
  14. package/dist/Form/Label.svelte +37 -0
  15. package/dist/Form/Label.svelte.d.ts +9 -0
  16. package/dist/Form/Select/Select.svelte +457 -0
  17. package/dist/Form/Select/Select.svelte.d.ts +22 -0
  18. package/dist/Form/Select/selectState.svelte.d.ts +4 -0
  19. package/dist/Form/Select/selectState.svelte.js +1 -0
  20. package/dist/Form/TextArea/TextArea.svelte +9 -27
  21. package/dist/Form/TextArea/TextArea.svelte.d.ts +2 -2
  22. package/dist/Header/Header.svelte +29 -33
  23. package/dist/Header/Header.svelte.d.ts +2 -3
  24. package/dist/Header/HeaderAccount.svelte +8 -6
  25. package/dist/Header/HeaderLoader.svelte +2 -2
  26. package/dist/Header/HeaderLogo.svelte +7 -4
  27. package/dist/Header/HeaderLogo.svelte.d.ts +14 -6
  28. package/dist/Menu/Menu.svelte +11 -11
  29. package/dist/Menu/MenuItem.svelte +7 -11
  30. package/dist/Modal/Modal.svelte +84 -27
  31. package/dist/Modal/Modal.svelte.d.ts +2 -9
  32. package/dist/Modal/ModalContent.svelte +4 -77
  33. package/dist/Modal/ModalContent.svelte.d.ts +2 -3
  34. package/dist/Modal/ModalFooter.svelte +17 -58
  35. package/dist/Modal/ModalFooter.svelte.d.ts +5 -5
  36. package/dist/Modal/ModalHeader.svelte +49 -31
  37. package/dist/Modal/ModalHeader.svelte.d.ts +5 -4
  38. package/dist/Modal/modalState.svelte.d.ts +15 -0
  39. package/dist/Modal/modalState.svelte.js +1 -0
  40. package/dist/Notification/Notification.svelte +69 -0
  41. package/dist/Notification/Notification.svelte.d.ts +4 -0
  42. package/dist/Notification/notificationState.svelte.d.ts +9 -0
  43. package/dist/Notification/notificationState.svelte.js +1 -0
  44. package/dist/ProgressPage/ProgressPage.svelte +95 -0
  45. package/dist/ProgressPage/ProgressPage.svelte.d.ts +11 -0
  46. package/dist/ProgressWizard/ProgressWizard.svelte +271 -278
  47. package/dist/ProgressWizard/ProgressWizard.svelte.d.ts +11 -13
  48. package/dist/ProgressWizard/progressWizardState.svelte.d.ts +6 -0
  49. package/dist/ProgressWizard/progressWizardState.svelte.js +1 -0
  50. package/dist/Search/Search.svelte +161 -0
  51. package/dist/Search/Search.svelte.d.ts +10 -0
  52. package/dist/Spinner/Spinner.svelte +23 -34
  53. package/dist/Spinner/Spinner.svelte.d.ts +3 -2
  54. package/dist/Toast/Toast.svelte +109 -42
  55. package/dist/Toast/toastState.svelte.d.ts +7 -3
  56. package/dist/Toast/toastState.svelte.js +13 -10
  57. package/dist/Tooltip/Tooltip.svelte +0 -2
  58. package/dist/index.d.ts +10 -2
  59. package/dist/index.js +7 -2
  60. package/package.json +4 -6
package/README.md CHANGED
@@ -15,32 +15,88 @@ npm install @softwareone/swo-spi-svelte5-library
15
15
  Import the components you need into your Svelte application:
16
16
 
17
17
  ```javascript
18
- import { Button,
19
- Modal,
20
- Spinner,
21
- Toaster,
22
- addToast,
23
- type Toast,
24
- Toggle,
25
- Header,
26
- Chips,
27
- Breadcrumbs,
28
- addBreadcrumbsNameMap,
29
- type BreadcrumbsNameMap,
30
- Footer,
31
- Card
32
- } from '@softwareone/swo-spi-svelte5-library';
18
+ import {
19
+ Avatar,
20
+ Breadcrumbs,
21
+ Button,
22
+ Card,
23
+ Chips,
24
+ ErrorPage,
25
+ Footer,
26
+ Header,
27
+ HeaderAccount,
28
+ HeaderLoader,
29
+ HeaderLogo,
30
+ HighlightPanel,
31
+ Input,
32
+ Menu,
33
+ Modal,
34
+ ProgressWizard,
35
+ Sidebar,
36
+ Tabs,
37
+ TextArea,
38
+ Toaster,
39
+ Toggle,
40
+ Tooltip
41
+ } from '@softwareone/swo-spi-svelte5-library';
42
+ ```
43
+
44
+ Import the types you need into your Svelte application:
45
+
46
+ ```javascript
47
+ import {
48
+ type BreadcrumbsNameMap,
49
+ type HighlightPanelColumn,
50
+ type MenuItem,
51
+ type ModalProps,
52
+ type ProgressWizardStep,
53
+ type Tab,
54
+ type Toast
55
+ } from '@softwareone/swo-spi-svelte5-library';
33
56
  ```
34
57
 
35
58
  # List of components
36
59
 
60
+ - Avatar
61
+ - Breadcrumbs
37
62
  - Button
63
+ - Card
64
+ - Chips
65
+ - ErrorPage
66
+ - Footer
67
+ - Form
68
+ - Input
69
+ - TextArea
70
+ - Toggle
71
+ - Header (including a loader)
72
+ - HeaderAccount
73
+ - HeaderLoader
74
+ - HeaderLogo
75
+ - HighlightPanel
76
+ - Menu
77
+ - Sidebar
38
78
  - Modal
79
+ - ProgressWizard
39
80
  - Spinner
81
+ - Tabs
40
82
  - Toaster
41
- - Toggle
42
- - Header (including a loader)
83
+ - Tooltip
84
+
85
+ # List of types per component
86
+
43
87
  - Breadcrumbs
88
+ - BreadcrumbsNameMap
44
89
  - Chips
45
- - Footer
46
- - Card
90
+ - ChipType
91
+ - HighlightPanel
92
+ - ColumnType
93
+ - HighlightPanelColumn
94
+ - ImageType
95
+ - Menu
96
+ - MenuItem
97
+ - Modal
98
+ - ModalProps
99
+ - ProgressWizard
100
+ - ProgressWizardStep
101
+ - Tab
102
+ - Toast
@@ -0,0 +1,89 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+
4
+ interface AccordionProps {
5
+ title: string;
6
+ disableBorder?: boolean;
7
+ content: Snippet;
8
+ }
9
+
10
+ let { title, disableBorder = false, content }: AccordionProps = $props();
11
+
12
+ let isOpen = $state(false);
13
+
14
+ const toggleAccordion = () => {
15
+ isOpen = !isOpen;
16
+ };
17
+ </script>
18
+
19
+ <aside class="accordion-container" class:border={!disableBorder}>
20
+ <div class="accordion-content">
21
+ <section class="header" class:is-open={isOpen}>
22
+ <button class="button" onclick={toggleAccordion}>
23
+ <span class="material-icons-outlined icon-span">
24
+ {isOpen ? 'keyboard_arrow_down' : 'keyboard_arrow_right'}
25
+ </span>
26
+ </button>
27
+
28
+ <h2 class="header-title">{title}</h2>
29
+ </section>
30
+
31
+ {#if isOpen}
32
+ {@render content()}
33
+ {/if}
34
+ </div>
35
+ </aside>
36
+
37
+ <style>
38
+ .accordion-container {
39
+ width: 100%;
40
+ height: 100%;
41
+ padding: 32px;
42
+ display: flex;
43
+
44
+ --border-color: #e0e5e8;
45
+ --color: #472aff;
46
+ }
47
+
48
+ .accordion-content {
49
+ flex-direction: column;
50
+ flex: 1 1 0;
51
+ gap: 4px;
52
+ display: flex;
53
+ font-size: 14px;
54
+ line-height: 20px;
55
+ }
56
+
57
+ .is-open {
58
+ padding-bottom: 10px;
59
+ }
60
+
61
+ .header {
62
+ gap: 16px;
63
+ display: inline-flex;
64
+ }
65
+
66
+ .header-title {
67
+ font-weight: 600;
68
+ }
69
+
70
+ .border {
71
+ border: 1px solid var(--border-color);
72
+ border-radius: 8px;
73
+ }
74
+
75
+ .button {
76
+ background: transparent;
77
+ border: none;
78
+ cursor: pointer;
79
+ border-radius: 50%;
80
+ display: flex;
81
+ align-items: center;
82
+ justify-content: center;
83
+ }
84
+
85
+ .icon-span {
86
+ color: var(--color);
87
+ font-size: 20px;
88
+ }
89
+ </style>
@@ -0,0 +1,9 @@
1
+ import type { Snippet } from 'svelte';
2
+ interface AccordionProps {
3
+ title: string;
4
+ disableBorder?: boolean;
5
+ content: Snippet;
6
+ }
7
+ declare const Accordion: import("svelte").Component<AccordionProps, {}, "">;
8
+ type Accordion = ReturnType<typeof Accordion>;
9
+ export default Accordion;
@@ -2,7 +2,7 @@
2
2
  import type { Snippet } from 'svelte';
3
3
  import type { HTMLButtonAttributes } from 'svelte/elements';
4
4
 
5
- type Variant = 'primary' | 'secondary' | 'outline';
5
+ type Variant = 'primary' | 'secondary' | 'outline' | 'outline-none';
6
6
  type VariantColor = 'primary' | 'danger';
7
7
 
8
8
  interface ButtonProps extends HTMLButtonAttributes {
@@ -78,6 +78,17 @@
78
78
  background: #eaecff;
79
79
  }
80
80
 
81
+ .btn-outline-none-primary {
82
+ border: none;
83
+ background: #fff;
84
+ color: #472aff;
85
+ }
86
+
87
+ .btn-outline-none-primary:hover:not(:disabled),
88
+ .btn-outline-none-primary:focus:not(:disabled) {
89
+ background: #e0e5e8;
90
+ }
91
+
81
92
  .btn-primary-danger {
82
93
  background: #dc182c;
83
94
  color: #fff;
@@ -1,6 +1,6 @@
1
1
  import type { Snippet } from 'svelte';
2
2
  import type { HTMLButtonAttributes } from 'svelte/elements';
3
- type Variant = 'primary' | 'secondary' | 'outline';
3
+ type Variant = 'primary' | 'secondary' | 'outline' | 'outline-none';
4
4
  type VariantColor = 'primary' | 'danger';
5
5
  interface ButtonProps extends HTMLButtonAttributes {
6
6
  variant?: Variant;
@@ -2,24 +2,20 @@
2
2
  import type { Snippet } from 'svelte';
3
3
 
4
4
  interface CardProps {
5
- alignItems?: 'left' | 'center' | 'right';
6
5
  type?: 'layout' | 'highlight';
7
6
  children?: Snippet;
8
7
  }
9
8
 
10
- let { alignItems = 'left', type = 'layout', children }: CardProps = $props();
9
+ let { type = 'layout', children }: CardProps = $props();
11
10
  </script>
12
11
 
13
- <div class="card card-{type}" data-align={alignItems}>
12
+ <div class="card card-{type}">
14
13
  {@render children?.()}
15
14
  </div>
16
15
 
17
16
  <style>
18
17
  .card {
19
- display: inline-flex;
20
- flex-direction: column;
21
18
  width: 100%;
22
- min-width: 222px;
23
19
  min-height: var(--card-min-height, auto);
24
20
  background: #fff;
25
21
  margin-bottom: 24px;
@@ -33,14 +29,4 @@
33
29
  .card-layout {
34
30
  --card-min-height: 100vh;
35
31
  }
36
-
37
- .card[data-align='left'] {
38
- align-items: flex-start;
39
- }
40
- .card[data-align='center'] {
41
- align-items: center;
42
- }
43
- .card[data-align='right'] {
44
- align-items: flex-end;
45
- }
46
32
  </style>
@@ -1,6 +1,5 @@
1
1
  import type { Snippet } from 'svelte';
2
2
  interface CardProps {
3
- alignItems?: 'left' | 'center' | 'right';
4
3
  type?: 'layout' | 'highlight';
5
4
  children?: Snippet;
6
5
  }
@@ -1,74 +1,71 @@
1
1
  <script lang="ts">
2
- import { ChipType } from '../index.js';
2
+ import { ChipType } from './chipsState.svelte.js';
3
3
 
4
4
  interface ChipsProps {
5
5
  type?: ChipType;
6
6
  text?: string;
7
7
  }
8
8
 
9
- let { type, text }: ChipsProps = $props();
10
-
11
- type = type || ChipType.Info;
12
- text = text || type.charAt(0).toUpperCase() + type.slice(1); // Default to capitalized type
13
-
14
- let className = `chip chip-${type}`;
9
+ let { type = ChipType.Info, text = type.charAt(0).toUpperCase() + type.slice(1) }: ChipsProps =
10
+ $props();
15
11
  </script>
16
12
 
17
- <div class={className}>
13
+ <div class="chip {type}">
18
14
  {text}
19
15
  </div>
20
16
 
21
17
  <style>
22
18
  .chip {
23
- display: inline-flex;
24
- padding: 2px 8px;
25
- align-items: center;
26
- gap: 8px;
27
- border-radius: 4px;
19
+ display: inline-block;
28
20
  font-size: 14px;
29
- font-style: normal;
30
- font-weight: 400;
21
+ font-weight: 500;
31
22
  line-height: 20px;
32
23
  background: var(--chip-bg);
33
24
  color: var(--chip-text);
25
+ padding: 2px 8px;
26
+ border-radius: 4px;
27
+ cursor: default;
34
28
  }
35
29
 
36
30
  .chip:hover {
37
- background: var(--chip-hover);
31
+ background: var(--chip-bg-hover);
38
32
  }
39
33
 
40
34
  .chip:focus {
41
- background: var(--chip-hover);
42
- box-shadow: 0px 0px 0px 3px var(--chip-hover);
35
+ box-shadow: 0px 0px 0px 3px #959bff;
43
36
  }
44
-
45
- .chip-info {
46
- --chip-bg: #eaecff;
37
+ .chip.info {
47
38
  --chip-text: #3520bf;
48
- --chip-hover: #959bff;
39
+ --chip-bg: #eaecff;
40
+ --chip-text-hover: #2b1999;
41
+ --chip-bg-hover: #959bff;
49
42
  }
50
43
 
51
- .chip-success {
52
- --chip-bg: #e6f9f2;
44
+ .chip.success {
53
45
  --chip-text: #00784d;
54
- --chip-hover: #80e1ae;
46
+ --chip-bg: #e6f9f2;
47
+ --chip-text-hover: #005838;
48
+ --chip-bg-hover: #80e1ae;
55
49
  }
56
50
 
57
- .chip-warning {
58
- --chip-bg: #fdf2e9;
51
+ .chip.warning {
59
52
  --chip-text: #a15d26;
60
- --chip-hover: #f1b178;
53
+ --chip-bg: #fdf2e9;
54
+ --chip-text-hover: #733f11;
55
+ --chip-bg-hover: #f1b178;
61
56
  }
62
57
 
63
- .chip-error {
64
- --chip-bg: #fce8ea;
58
+ .chip.error {
65
59
  --chip-text: #bb1425;
66
- --chip-hover: #ee8c96;
60
+ --chip-bg: #fce8ea;
61
+ --chip-text-hover: #8f101d;
62
+ --chip-bg-hover: #ee8c96;
67
63
  }
68
64
 
69
- .chip-neutral {
70
- --chip-bg: #f4f6f8;
65
+ .chip.neutral {
71
66
  --chip-text: #434952;
72
- --chip-hover: #e0e5e8;
67
+ --chip-bg: #f4f6f8;
68
+ --chip-text-hover: #25282d;
69
+ --chip-bg-hover: #e0e5e8;
73
70
  }
74
71
  </style>
@@ -1,4 +1,4 @@
1
- import { ChipType } from '../index.js';
1
+ import { ChipType } from './chipsState.svelte.js';
2
2
  interface ChipsProps {
3
3
  type?: ChipType;
4
4
  text?: string;
@@ -2,22 +2,20 @@
2
2
  import { goto } from '$app/navigation';
3
3
  import { page } from '$app/state';
4
4
 
5
- import { StatusCodes } from 'http-status-codes';
6
-
7
5
  import FeedbackIcon from '../assets/icons/feedback.svg';
8
6
  import { Button } from '../index.js';
9
7
 
10
8
  interface ErrorPageProps {
11
- status: StatusCodes;
9
+ status: number;
12
10
  title?: string;
13
11
  }
14
12
 
15
13
  let { status, title }: ErrorPageProps = $props();
16
14
 
17
15
  const errorTitle: Record<number, string> = {
18
- [StatusCodes.NOT_FOUND]: 'Page not found',
19
- [StatusCodes.FORBIDDEN]: 'Access denied',
20
- [StatusCodes.INTERNAL_SERVER_ERROR]: 'An unexpected error occurred'
16
+ [404]: 'Page not found',
17
+ [403]: 'Access denied',
18
+ [500]: 'An unexpected error occurred'
21
19
  };
22
20
  </script>
23
21
 
@@ -26,7 +24,7 @@
26
24
 
27
25
  <div class="feedback-detail">
28
26
  <h1>{title || errorTitle[status]}</h1>
29
- {#if status === StatusCodes.NOT_FOUND}
27
+ {#if status === 404}
30
28
  <div>
31
29
  <p>We couldn’t find the page:</p>
32
30
  <p class="link">{page.url}</p>
@@ -79,6 +77,7 @@
79
77
 
80
78
  .feedback-detail > h1 {
81
79
  font-size: 24px;
80
+ font-weight: bold;
82
81
  }
83
82
 
84
83
  .feedback-detail .link {
@@ -1,6 +1,5 @@
1
- import { StatusCodes } from 'http-status-codes';
2
1
  interface ErrorPageProps {
3
- status: StatusCodes;
2
+ status: number;
4
3
  title?: string;
5
4
  }
6
5
  declare const ErrorPage: import("svelte").Component<ErrorPageProps, {}, "">;
@@ -1,17 +1,19 @@
1
1
  <script lang="ts">
2
2
  import type { HTMLInputAttributes } from 'svelte/elements';
3
3
  import InputIcon from './InputIcon.svelte';
4
+ import Label from '../Label.svelte';
4
5
 
5
6
  type InputType = 'text' | 'password' | 'number' | 'date' | 'money';
6
7
 
7
8
  interface InputProps extends Omit<HTMLInputAttributes, 'type' | 'value'> {
8
9
  label?: string;
9
10
  type?: InputType;
10
- value?: string | number;
11
+ value?: string | number | null;
11
12
  optional?: boolean;
12
- error?: string;
13
+ error?: string | string[];
13
14
  description?: string;
14
15
  currency?: string;
16
+ disableValidationColor?: boolean;
15
17
  }
16
18
 
17
19
  let {
@@ -19,14 +21,15 @@
19
21
  type = 'text',
20
22
  value = $bindable(''),
21
23
  optional = false,
24
+ required = false,
22
25
  error,
23
26
  description,
24
27
  currency,
25
28
  id,
26
29
  disabled,
27
30
  readonly,
28
- required,
29
31
  oninput,
32
+ disableValidationColor = false,
30
33
  ...props
31
34
  }: InputProps = $props();
32
35
 
@@ -45,39 +48,22 @@
45
48
  money: 'number',
46
49
  password: isPasswordVisible ? 'text' : 'password'
47
50
  });
48
-
49
- const handleInput = (event: Event): void => {
50
- const target = event.target as HTMLInputElement;
51
- value = type === 'number' || type === 'money' ? target.valueAsNumber : target.value;
52
- oninput?.(event as Event & { currentTarget: EventTarget & HTMLInputElement });
53
- };
54
51
  </script>
55
52
 
56
53
  <div class="form-container">
57
- {#if label}
58
- <div class="form-label-container">
59
- <label for={inputId}>{label}</label>
60
- {#if required}
61
- <span class="form-label-required">Required</span>
62
- {:else if optional}
63
- <span class="form-label-optional">Optional</span>
64
- {/if}
65
- </div>
66
- {/if}
67
-
54
+ <Label {label} {id} {optional} {required} />
68
55
  <div
69
56
  class={[
70
57
  'form-input-wrapper',
71
- isInvalid && 'error',
72
- isValid && 'success',
58
+ !disableValidationColor && [isInvalid && 'error', isValid && 'success'],
73
59
  type === 'money' && currency && 'money-with-icon'
74
60
  ]}
75
61
  >
76
62
  <input
63
+ bind:value
77
64
  {...props}
78
65
  id={inputId}
79
66
  type={transformationType[type] ?? type}
80
- {value}
81
67
  {disabled}
82
68
  {readonly}
83
69
  class={[
@@ -88,7 +74,6 @@
88
74
  showDatePicker && 'form-input-date'
89
75
  ]}
90
76
  aria-invalid={isInvalid}
91
- oninput={handleInput}
92
77
  />
93
78
 
94
79
  {#if type === 'money' && currency}
@@ -102,7 +87,7 @@
102
87
  type === 'password' && hasStatus && 'form-input-icon-container-password'
103
88
  ]}
104
89
  >
105
- {#if hasStatus}
90
+ {#if !disableValidationColor && hasStatus}
106
91
  <InputIcon type={isInvalid ? 'error' : 'success'} isDateInput={showDatePicker} />
107
92
  {/if}
108
93
 
@@ -120,7 +105,7 @@
120
105
  {/if}
121
106
  {#if isInvalid}
122
107
  <p class="form-message form-message-error">
123
- {error}
108
+ {Array.isArray(error) ? error[0] : error}
124
109
  </p>
125
110
  {/if}
126
111
  </div>
@@ -134,20 +119,6 @@
134
119
  line-height: 20px;
135
120
  }
136
121
 
137
- .form-label-container {
138
- display: flex;
139
- gap: 8px;
140
- font-weight: 500;
141
- }
142
-
143
- .form-label-optional {
144
- color: #6b7180;
145
- }
146
-
147
- .form-label-required {
148
- color: #dc2626;
149
- }
150
-
151
122
  .form-message {
152
123
  font-size: 12px;
153
124
  }
@@ -259,7 +230,7 @@
259
230
  right: 43px;
260
231
  top: 0;
261
232
  bottom: 0;
262
- width: 1px;
233
+ width: 0.5px;
263
234
  background-color: #6b7180;
264
235
  z-index: 1;
265
236
  }
@@ -327,7 +298,7 @@
327
298
  left: 0;
328
299
  top: -8px;
329
300
  bottom: -8px;
330
- width: 1px;
301
+ width: 0.5px;
331
302
  background-color: #6b7180;
332
303
  z-index: 1;
333
304
  }
@@ -351,7 +322,9 @@
351
322
  border-color: #008556;
352
323
  }
353
324
 
354
- .form-input-wrapper.success:hover:not(:has(.form-input:disabled)):not(:has(.form-input:read-only)),
325
+ .form-input-wrapper.success:hover:not(:has(.form-input:disabled)):not(
326
+ :has(.form-input:read-only)
327
+ ),
355
328
  .form-input-wrapper.success:focus-within {
356
329
  border-color: #10b981;
357
330
  }
@@ -3,11 +3,12 @@ type InputType = 'text' | 'password' | 'number' | 'date' | 'money';
3
3
  interface InputProps extends Omit<HTMLInputAttributes, 'type' | 'value'> {
4
4
  label?: string;
5
5
  type?: InputType;
6
- value?: string | number;
6
+ value?: string | number | null;
7
7
  optional?: boolean;
8
- error?: string;
8
+ error?: string | string[];
9
9
  description?: string;
10
10
  currency?: string;
11
+ disableValidationColor?: boolean;
11
12
  }
12
13
  declare const Input: import("svelte").Component<InputProps, {}, "value">;
13
14
  type Input = ReturnType<typeof Input>;
@@ -0,0 +1,37 @@
1
+ <script lang="ts">
2
+ interface LabelProps {
3
+ label?: string;
4
+ id?: string | null;
5
+ required?: boolean | null;
6
+ optional?: boolean;
7
+ }
8
+
9
+ let { label, id, required, optional }: LabelProps = $props();
10
+ </script>
11
+
12
+ {#if label}
13
+ <div class="form-label-container">
14
+ <label for={id}>{label}</label>
15
+ {#if required}
16
+ <span class="form-label-required">Required</span>
17
+ {:else if optional}
18
+ <span class="form-label-optional">Optional</span>
19
+ {/if}
20
+ </div>
21
+ {/if}
22
+
23
+ <style>
24
+ .form-label-container {
25
+ display: flex;
26
+ gap: 8px;
27
+ font-weight: 500;
28
+ }
29
+
30
+ .form-label-optional {
31
+ color: #6b7180;
32
+ }
33
+
34
+ .form-label-required {
35
+ color: #dc2626;
36
+ }
37
+ </style>
@@ -0,0 +1,9 @@
1
+ interface LabelProps {
2
+ label?: string;
3
+ id?: string | null;
4
+ required?: boolean | null;
5
+ optional?: boolean;
6
+ }
7
+ declare const Label: import("svelte").Component<LabelProps, {}, "">;
8
+ type Label = ReturnType<typeof Label>;
9
+ export default Label;