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