@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
@@ -1,355 +1,348 @@
1
1
  <script lang="ts">
2
- import { addToast } from '../Toast/toastState.svelte';
2
+ import { type Snippet } from 'svelte';
3
3
 
4
- interface Step {
5
- title: string;
6
- description: string;
7
- isValid?: boolean;
8
- }
4
+ import { Button, ErrorPage, type ProgressWizardStep } from '../index.js';
9
5
 
10
- interface StepProps {
11
- steps: Step[];
12
- currentStep?: number;
13
- isFormValid?: boolean;
14
- onFinalStepAction?: () => void;
15
- useAsPopUp?: boolean;
16
- children?: () => any;
6
+ interface ProgressWizardProps {
7
+ steps: ProgressWizardStep[];
8
+ readonly?: boolean;
9
+ currentStep: number;
10
+ lastActiveStep: number;
11
+ content: Snippet;
12
+ additionalButtons: Snippet;
13
+ oncancel: VoidFunction;
17
14
  }
18
15
 
19
16
  let {
20
- steps = $bindable(),
21
- currentStep = $bindable(1),
22
- isFormValid = $bindable(),
23
- onFinalStepAction,
24
- useAsPopUp = false,
25
- children
26
- }: StepProps = $props();
27
-
28
- steps = steps.map((step) => ({
29
- ...step,
30
- isValid: step.isValid ?? true
31
- }));
32
-
33
- let completedSteps = $state<Set<number>>(new Set());
34
- let stepsFormInstance: any;
35
-
36
- const goToStep = (step: number) => {
37
- if (step <= steps.length) {
38
- for (let i = 1; i <= step; i++) {
39
- completedSteps.add(i);
40
- }
41
- currentStep = step;
42
- }
17
+ steps,
18
+ readonly = false,
19
+ currentStep = $bindable(0),
20
+ lastActiveStep = $bindable(0),
21
+ content,
22
+ additionalButtons,
23
+ oncancel
24
+ }: ProgressWizardProps = $props();
25
+
26
+ const allStepsDisabled: boolean = steps.every((step) => step.disabled);
27
+ const firstActiveStep: number = steps.findIndex((step) => !step.disabled) + 1;
28
+
29
+ const onclickNext = () => {
30
+ const nextStepIndex = steps.slice(currentStep).findIndex((step) => !step.disabled);
31
+ currentStep = currentStep + nextStepIndex + 1;
43
32
  };
44
33
 
45
- const nextStep = () => {
46
- if (stepsFormInstance && !stepsFormInstance.validateCurrentStep()) {
47
- isFormValid = false;
48
- return;
49
- }
50
- if (currentStep < steps.length) {
51
- goToStep(currentStep + 1);
52
- } else {
53
- addToast({
54
- type: 'success',
55
- message: 'Form submitted successfully!'
56
- });
57
- }
34
+ const onclickBack = () => {
35
+ const previousStepIndex = steps
36
+ .slice(0, currentStep - 1)
37
+ .reverse()
38
+ .findIndex((step) => !step.disabled);
39
+
40
+ currentStep = currentStep - previousStepIndex - 1;
58
41
  };
59
42
 
60
- const previousStep = () => {
61
- if (currentStep > 1) goToStep(currentStep - 1);
43
+ const stepToStart = (): number => {
44
+ if (readonly && allStepsDisabled) return -1;
45
+ if (readonly && !allStepsDisabled) return steps.length;
46
+ return firstActiveStep;
62
47
  };
63
48
 
64
- const onClose = () => {
65
- if (useAsPopUp) {
66
- // Logic to close the pop-up
49
+ currentStep = stepToStart();
50
+ lastActiveStep = steps.findLastIndex((step) => !step.disabled) + 1;
51
+
52
+ $effect(() => {
53
+ if (!readonly) {
54
+ currentStep = firstActiveStep;
67
55
  }
68
- };
56
+ });
69
57
  </script>
70
58
 
71
59
  <div class="progress-wizard">
72
- <!-- Header -->
73
- <div class="progress-header">
74
- <div class="title">Create workspace</div>
75
- <div class="header-actions">
76
- {#if useAsPopUp}
77
- <button class="link close" onclick={onClose}>
78
- <span class="material-icons-outlined">close</span>
79
- </button>
60
+ <section class="progress-wizard-container">
61
+ <ol class={['progress-wizard-steps', readonly ? 'readonly' : 'editing-mode']}>
62
+ {#each steps as step, index}
63
+ {@const stepIndex = index + 1}
64
+ {@const isActive = stepIndex === currentStep}
65
+ {@const isPreviousStep = currentStep > stepIndex}
66
+ {@const isValid = isPreviousStep && step.isValid}
67
+ {@const isInvalid = isPreviousStep && !step.isValid}
68
+ {@const disabled = step.disabled}
69
+
70
+ {@const circleContent = (): string => {
71
+ if (isActive) return stepIndex.toString();
72
+ if (readonly || disabled) return 'ー';
73
+ if (isValid) return '✔';
74
+ if (isInvalid) return '✖';
75
+ return stepIndex.toString();
76
+ }}
77
+
78
+ <li
79
+ class={[
80
+ 'progress-wizard-step',
81
+ isActive && 'active',
82
+ !readonly && [
83
+ isPreviousStep && 'previous',
84
+ isValid && 'valid',
85
+ isInvalid && 'invalid',
86
+ disabled && 'disabled'
87
+ ]
88
+ ]}
89
+ >
90
+ <div class="time-line">
91
+ <span class="circle">
92
+ {circleContent()}
93
+ </span>
94
+ <span class="line"></span>
95
+ </div>
96
+ <button
97
+ type="button"
98
+ class="details"
99
+ disabled={disabled || readonly}
100
+ onclick={() => (currentStep = stepIndex)}
101
+ >
102
+ <h2>{step.title}</h2>
103
+ {#if step.description}
104
+ <p>{step.description}</p>
105
+ {/if}
106
+ </button>
107
+ </li>
108
+ {/each}
109
+ </ol>
110
+ <article class="progress-wizard-content">
111
+ {#if allStepsDisabled}
112
+ <ErrorPage status={403} title="All steps disabled" />
113
+ {:else}
114
+ {@render content()}
80
115
  {/if}
81
- </div>
82
- </div>
83
-
84
- <!-- Sidebar + Content -->
85
- <div class="progress-body">
86
- <!-- Sidebar -->
87
- <div class="progress-sidebar">
88
- <ol>
89
- {#each steps as step, index}
90
- <li
91
- class:completed={completedSteps.has(index + 1)}
92
- class:active={currentStep === index + 1}
116
+ </article>
117
+ </section>
118
+ <section class="progress-wizard-footer">
119
+ <Button variant="outline-none" onclick={oncancel}>Cancel</Button>
120
+
121
+ <div class="actions">
122
+ {#if !allStepsDisabled}
123
+ {#if !readonly}
124
+ <Button
125
+ variant="secondary"
126
+ disabled={currentStep === firstActiveStep}
127
+ onclick={onclickBack}>Back</Button
93
128
  >
94
- <button
95
- type="button"
96
- onclick={() => goToStep(index + 1)}
97
- class="step-button"
98
- class:done={index + 1 < currentStep}
99
- >
100
- <div class="step-line-wrapper">
101
- {#if index < steps.length - 1}
102
- <div class="step-line"></div>
103
- {/if}
104
- <span class="step-icon" class:error={!step.isValid && index + 1 < currentStep}>
105
- {#if index + 1 < currentStep && step.isValid}
106
-
107
- {:else if !step.isValid && index + 1 < currentStep}
108
- x
109
- {:else}
110
- {index + 1}
111
- {/if}
112
- </span>
113
- </div>
114
- <div class="step-details">
115
- <strong>{step.title}</strong>
116
- <small>{step.description}</small>
117
- </div>
118
- </button>
119
- </li>
120
- {/each}
121
- </ol>
122
- </div>
123
129
 
124
- <!-- Main Content -->
125
- <div class="progress-content">
126
- <div class="step-content">
127
- {@render children?.()}
128
- </div>
129
- </div>
130
- </div>
131
-
132
- <!-- Footer -->
133
- <div class="progress-footer">
134
- <button class="btn link">Cancel</button>
135
- <div class="action-buttons">
136
- <button class="btn secondary" onclick={previousStep} disabled={currentStep === 1}>Back</button
137
- >
138
- <button
139
- class="btn primary"
140
- onclick={nextStep}
141
- disabled={currentStep === steps.length && !isFormValid}
142
- >
143
- {currentStep === steps.length ? 'Create' : 'Next'}
144
- </button>
130
+ {#if currentStep < lastActiveStep}
131
+ <Button variant="primary" onclick={onclickNext}>Next</Button>
132
+ {/if}
133
+ {/if}
134
+
135
+ {@render additionalButtons()}
136
+ {/if}
145
137
  </div>
146
- </div>
138
+ </section>
147
139
  </div>
148
140
 
149
141
  <style>
150
142
  .progress-wizard {
143
+ --primary-color: #472aff;
144
+ --red-5: #c41e3a;
145
+ --red-2: #fdedec;
146
+ --info-1: #eaecff;
147
+ --gray-1: #f4f6f8;
148
+ --gray-2: #e0e5e8;
149
+ --gray-3: #aeb1b9;
150
+ --gray-4: #6b7180;
151
+ --border-wizard: 1px solid var(--gray-3);
152
+ --circle-size: 32px;
153
+
151
154
  display: flex;
152
155
  flex-direction: column;
153
156
  width: 100%;
154
- max-width: 97vw;
155
- margin: 0 auto;
156
- background: #fff;
157
- border-radius: 8px;
158
- box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
159
- overflow: hidden;
160
- font-size: 14px;
157
+ height: 100vh;
161
158
  }
162
159
 
163
- .progress-body {
160
+ .progress-wizard-container {
164
161
  display: flex;
165
- width: 100%;
162
+ flex: 1;
166
163
  }
167
164
 
168
- .progress-sidebar {
169
- width: 100%;
170
- min-width: 226px;
171
- max-width: 226px;
172
- min-height: 50vh;
173
- border-right: 1px solid #e6e6e6;
165
+ .progress-wizard-steps {
166
+ display: flex;
167
+ flex-direction: column;
168
+ width: fit-content;
169
+ max-width: 250px;
170
+ border-right: var(--border-wizard);
174
171
  }
175
172
 
176
- .progress-content {
177
- flex-grow: 1;
178
- padding: 24px;
179
- margin-bottom: -20px;
173
+ .progress-wizard-step {
174
+ display: grid;
175
+ grid-template-columns: auto 1fr;
176
+ max-height: 70px;
177
+ padding: 16px 24px;
178
+ gap: 8px;
179
+ align-items: center;
180
+ border: none;
180
181
  }
181
182
 
182
- .progress-header {
183
+ .time-line {
184
+ position: relative;
183
185
  display: flex;
186
+ flex-direction: column;
184
187
  align-items: center;
185
- justify-content: space-between;
186
- padding: 24px;
187
- gap: 16px;
188
- border-bottom: 2px solid transparent;
189
- border-image: linear-gradient(259deg, #00c9cd 16.32%, #472aff 59.03%, #392d9c 99.99%);
190
- border-image-slice: 1;
191
- }
192
-
193
- .progress-header .title {
194
- color: #000;
195
- font-size: 18px;
196
- font-weight: 600;
197
- line-height: 26px;
198
- flex: 1 0 0;
199
188
  }
200
189
 
201
- .progress-header .header-actions button span {
202
- font-size: 24px;
203
- }
204
-
205
- .progress-sidebar li {
190
+ .circle {
206
191
  display: flex;
207
- position: relative;
208
- cursor: default;
209
- padding: 16px 24px;
210
- gap: 8px;
211
- color: inherit;
192
+ width: var(--circle-size);
193
+ height: var(--circle-size);
194
+ align-items: center;
195
+ justify-content: center;
196
+ font-size: 12px;
197
+ font-weight: 600;
198
+ border-radius: 50%;
199
+ background: var(--info-1);
200
+ color: var(--primary-color);
212
201
  }
213
202
 
214
- .progress-sidebar li.completed {
215
- color: #4caf50;
203
+ .line {
204
+ position: absolute;
205
+ top: var(--circle-size);
206
+ width: 1px;
207
+ height: 50px;
208
+ background: var(--gray-2);
209
+ transition: background 500ms ease;
216
210
  }
217
211
 
218
- .progress-sidebar li.active {
219
- color: #472aff;
212
+ .progress-wizard-step:last-child .time-line .line {
213
+ display: none;
220
214
  }
221
215
 
222
- .step-button {
223
- all: unset;
224
- width: 100%;
225
- display: flex;
226
- align-items: flex-start;
227
- border-radius: 4px;
216
+ .details {
217
+ padding: 4px 8px;
218
+ text-align: left;
219
+ border: none;
220
+ border-radius: 8px;
221
+ background: transparent;
228
222
  cursor: pointer;
229
- transition: background 0.3s;
230
- }
231
223
 
232
- .step-button:hover .step-icon,
233
- li.active .step-icon {
234
- border-color: #472aff;
235
- }
224
+ h2 {
225
+ font-size: 16px;
226
+ font-weight: 600;
227
+ color: #000;
228
+ }
236
229
 
237
- .step-button:hover .step-details,
238
- .step-button:hover .step-details small,
239
- li.active .step-button .step-details small {
240
- color: #472aff;
230
+ p {
231
+ font-size: 12px;
232
+ word-break: keep-all;
233
+ color: var(--gray-4);
234
+ }
241
235
  }
242
236
 
243
- .step-icon {
244
- width: 24px;
245
- height: 24px;
246
- display: flex;
247
- align-items: center;
248
- justify-content: center;
249
- background: #eaecff;
250
- border: 2px solid #eaecff;
251
- border-radius: 50%;
252
- margin-right: 10px;
253
- font-size: 0.9rem;
254
- color: #472aff;
237
+ .details:hover {
238
+ background: var(--gray-1);
255
239
  }
256
240
 
257
- li .done .step-icon {
258
- background: #472aff;
259
- color: white;
260
- border-color: #472aff;
241
+ .details:focus-visible:not(:disabled) {
242
+ background: var(--gray-1);
243
+ box-shadow: 0px 0px 0px 3px var(--info-1);
244
+ outline: none;
261
245
  }
262
246
 
263
- .step-button .step-icon.error {
264
- background: #fce8ea;
265
- color: #bb1425;
266
- border-color: #bb1425;
247
+ .progress-wizard-content {
248
+ flex: 1;
249
+ padding: 24px;
267
250
  }
268
251
 
269
- .step-line-wrapper {
270
- position: relative;
252
+ .progress-wizard-footer {
271
253
  display: flex;
272
- flex-direction: column;
273
- align-items: center;
274
- justify-content: flex-start;
275
- margin-right: 10px;
276
- }
254
+ padding: 24px;
255
+ border-top: var(--border-wizard);
277
256
 
278
- .step-line {
279
- width: 1px;
280
- height: 40px;
281
- background: #e6e6e6;
282
- position: absolute;
283
- top: 100%;
284
- left: 37%;
285
- transform: translateX(-50%);
286
- z-index: 0;
287
- transition: background 0.3s ease;
257
+ .actions {
258
+ display: flex;
259
+ gap: 12px;
260
+ margin-left: auto;
261
+ }
288
262
  }
289
263
 
290
- li.completed .step-line,
291
- li .done .step-line {
292
- background: #472aff;
293
- }
264
+ .progress-wizard-step.active {
265
+ .time-line .circle {
266
+ border: 2px solid var(--primary-color);
267
+ }
294
268
 
295
- .step-details {
296
- display: flex;
297
- flex-direction: column;
298
- }
269
+ .details {
270
+ box-shadow: none;
271
+ background: transparent;
299
272
 
300
- .step-details strong {
301
- font-size: 16px;
273
+ h2,
274
+ p {
275
+ color: var(--primary-color);
276
+ }
277
+ }
302
278
  }
303
279
 
304
- .step-details small {
305
- font-size: 12px;
306
- color: #999;
307
- }
280
+ .progress-wizard-steps:is(.readonly) {
281
+ .progress-wizard-step:not(.active) {
282
+ .line {
283
+ background: var(--gray-2);
284
+ }
308
285
 
309
- .step-content {
310
- margin-bottom: 20px;
311
- }
286
+ .circle {
287
+ border: 2px solid var(--gray-2);
288
+ background: var(--gray-2);
289
+ color: var(--gray-4);
290
+ }
312
291
 
313
- .progress-footer {
314
- display: flex;
315
- justify-content: space-between;
316
- align-items: center;
317
- padding: 10px 20px;
318
- border-top: 1px solid #e6e6e6;
319
- }
292
+ .details {
293
+ h2 {
294
+ color: var(--gray-4);
295
+ }
296
+ p {
297
+ color: var(--gray-3);
298
+ }
299
+ }
320
300
 
321
- .btn {
322
- padding: 10px 20px;
323
- border-radius: 4px;
324
- border: none;
325
- cursor: pointer;
326
- font-size: 0.9rem;
301
+ .details:hover {
302
+ background: transparent;
303
+ cursor: not-allowed;
304
+ }
305
+ }
327
306
  }
328
307
 
329
- .btn.primary {
330
- background: #472aff;
331
- color: white;
332
- }
308
+ .progress-wizard-steps:is(.editing-mode) {
309
+ .progress-wizard-step.previous .time-line .line {
310
+ background: var(--primary-color);
311
+ }
333
312
 
334
- .btn.secondary {
335
- background: #eaecff;
336
- color: #472aff;
337
- margin-right: 10px;
338
- }
313
+ .progress-wizard-step.previous.valid .time-line .circle {
314
+ color: white;
315
+ background: var(--primary-color);
316
+ border: 2px solid var(--primary-color);
317
+ }
339
318
 
340
- .btn:disabled {
341
- cursor: not-allowed;
342
- opacity: 0.5;
343
- }
319
+ .progress-wizard-step.previous.invalid .time-line .circle {
320
+ color: var(--red-5);
321
+ background: var(--red-2);
322
+ border: 2px solid var(--red-5);
323
+ }
344
324
 
345
- .link {
346
- background: transparent;
347
- color: #472aff;
348
- font-size: 0.9rem;
349
- }
325
+ .progress-wizard-step:is(.disabled, .previous.disabled) {
326
+ .details {
327
+ h2 {
328
+ color: var(--gray-4);
329
+ }
330
+ p {
331
+ color: var(--gray-3);
332
+ }
333
+ }
334
+ .details:hover {
335
+ background: transparent;
336
+ cursor: not-allowed;
337
+ }
350
338
 
351
- .close {
352
- color: #25282d;
353
- border: none;
339
+ .time-line {
340
+ .circle {
341
+ color: var(--gray-4);
342
+ background: var(--gray-2);
343
+ border: 2px solid var(--gray-2);
344
+ }
345
+ }
346
+ }
354
347
  }
355
348
  </style>
@@ -1,16 +1,14 @@
1
- interface Step {
2
- title: string;
3
- description: string;
4
- isValid?: boolean;
1
+ import { type Snippet } from 'svelte';
2
+ import { type ProgressWizardStep } from '../index.js';
3
+ interface ProgressWizardProps {
4
+ steps: ProgressWizardStep[];
5
+ readonly?: boolean;
6
+ currentStep: number;
7
+ lastActiveStep: number;
8
+ content: Snippet;
9
+ additionalButtons: Snippet;
10
+ oncancel: VoidFunction;
5
11
  }
6
- interface StepProps {
7
- steps: Step[];
8
- currentStep?: number;
9
- isFormValid?: boolean;
10
- onFinalStepAction?: () => void;
11
- useAsPopUp?: boolean;
12
- children?: () => any;
13
- }
14
- declare const ProgressWizard: import("svelte").Component<StepProps, {}, "steps" | "currentStep" | "isFormValid">;
12
+ declare const ProgressWizard: import("svelte").Component<ProgressWizardProps, {}, "currentStep" | "lastActiveStep">;
15
13
  type ProgressWizard = ReturnType<typeof ProgressWizard>;
16
14
  export default ProgressWizard;
@@ -0,0 +1,6 @@
1
+ export type ProgressWizardStep = {
2
+ title: string;
3
+ description?: string;
4
+ isValid: boolean;
5
+ disabled: boolean;
6
+ };
@@ -0,0 +1 @@
1
+ export {};