@softwareone/spi-sv5-library 1.15.3 → 1.16.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.
- package/dist/components/controls/select/Select.svelte +4 -3
- package/dist/components/progress-wizard/ProgressWizard.svelte +49 -269
- package/dist/components/progress-wizard/ProgressWizard.svelte.d.ts +10 -1
- package/dist/components/progress-wizard/ProgressWizardHorizontal.svelte +66 -0
- package/dist/components/progress-wizard/ProgressWizardHorizontal.svelte.d.ts +4 -0
- package/dist/components/progress-wizard/ProgressWizardStep.svelte +251 -0
- package/dist/components/progress-wizard/ProgressWizardStep.svelte.d.ts +7 -0
- package/dist/components/progress-wizard/ProgressWizardVertical.svelte +88 -0
- package/dist/components/progress-wizard/ProgressWizardVertical.svelte.d.ts +9 -0
- package/dist/components/progress-wizard/context.d.ts +3 -1
- package/dist/components/progress-wizard/context.js +14 -0
- package/dist/components/progress-wizard/types.d.ts +21 -0
- package/dist/components/table/Body.svelte +13 -3
- package/dist/components/table/Body.svelte.d.ts +1 -0
- package/dist/components/table/Table.svelte +55 -9
- package/dist/components/table/Table.svelte.d.ts +39 -24
- package/dist/components/table/utils.d.ts +1 -1
- package/dist/components/table/utils.js +3 -2
- package/dist/utils/url.js +5 -3
- package/package.json +1 -1
|
@@ -243,12 +243,12 @@
|
|
|
243
243
|
<section
|
|
244
244
|
role="button"
|
|
245
245
|
tabindex="0"
|
|
246
|
-
class="dropdown-container
|
|
246
|
+
class="dropdown-container"
|
|
247
247
|
onclick={readonly ? undefined : onToggleListOptions}
|
|
248
248
|
onkeypress={readonly ? undefined : onToggleListOptions}
|
|
249
249
|
bind:this={dropdownContainer}
|
|
250
250
|
>
|
|
251
|
-
<div class="dropdown-container-selected-options">
|
|
251
|
+
<div class="dropdown-container-selected-options spi-text-regular-2">
|
|
252
252
|
{#if selectedOption || selectedOptions.length}
|
|
253
253
|
{#if multiple}
|
|
254
254
|
{#each selectedOptions as selectedOption, index (index)}
|
|
@@ -277,7 +277,7 @@
|
|
|
277
277
|
{#if showListOptions && !readonly}
|
|
278
278
|
<section
|
|
279
279
|
class={[
|
|
280
|
-
'dropdown-list',
|
|
280
|
+
'dropdown-list spi-text-regular-2',
|
|
281
281
|
positionStrategy === 'absolute' && 'upwards',
|
|
282
282
|
positionStrategy === 'fixed' && 'position-fixed'
|
|
283
283
|
]}
|
|
@@ -332,6 +332,7 @@
|
|
|
332
332
|
|
|
333
333
|
{#snippet dropdownOptionTemplate(option: SelectOption)}
|
|
334
334
|
<button
|
|
335
|
+
class="spi-text-regular-2"
|
|
335
336
|
type="button"
|
|
336
337
|
onclick={(event) => {
|
|
337
338
|
event.stopPropagation();
|
|
@@ -1,28 +1,51 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { untrack, type Snippet } from 'svelte';
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { type ProgressWizardStep } from '../../index.js';
|
|
5
|
+
import { setWizardContext } from './context.js';
|
|
6
|
+
import ProgressWizardHorizontal from './ProgressWizardHorizontal.svelte';
|
|
7
|
+
import ProgressWizardVertical from './ProgressWizardVertical.svelte';
|
|
5
8
|
|
|
6
|
-
interface
|
|
9
|
+
interface BaseProps {
|
|
7
10
|
steps: ProgressWizardStep[];
|
|
8
11
|
currentStep: number;
|
|
9
12
|
readonly?: boolean;
|
|
10
13
|
initialStep?: number;
|
|
11
14
|
content: Snippet;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface HorizontalProps extends BaseProps {
|
|
18
|
+
orientation: 'horizontal';
|
|
19
|
+
additionalButtons?: never;
|
|
20
|
+
oncancel?: never;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface VerticalProps extends BaseProps {
|
|
24
|
+
orientation?: 'vertical';
|
|
12
25
|
additionalButtons: Snippet<[lastActiveStep: number]>;
|
|
13
26
|
oncancel: VoidFunction;
|
|
14
27
|
}
|
|
15
28
|
|
|
29
|
+
type Props = VerticalProps | HorizontalProps;
|
|
30
|
+
|
|
16
31
|
let {
|
|
17
32
|
steps,
|
|
18
|
-
readonly = false,
|
|
19
33
|
currentStep = $bindable(0),
|
|
34
|
+
readonly = false,
|
|
20
35
|
initialStep,
|
|
21
36
|
content,
|
|
22
|
-
|
|
23
|
-
oncancel
|
|
37
|
+
...props
|
|
24
38
|
}: Props = $props();
|
|
25
39
|
|
|
40
|
+
setWizardContext({
|
|
41
|
+
getSteps: () => steps,
|
|
42
|
+
getReadonly: () => readonly,
|
|
43
|
+
getCurrentStep: () => currentStep,
|
|
44
|
+
setCurrentStep: (step: number) => {
|
|
45
|
+
currentStep = step;
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
|
|
26
49
|
const allStepsDisabled = $derived<boolean>(steps.every((step) => step.disabled));
|
|
27
50
|
const firstActiveStep = $derived<number>(steps.findIndex((step) => !step.disabled) + 1);
|
|
28
51
|
const lastActiveStep = $derived<number>(steps.findLastIndex((step) => !step.disabled) + 1);
|
|
@@ -63,86 +86,27 @@
|
|
|
63
86
|
</script>
|
|
64
87
|
|
|
65
88
|
<div class="progress-wizard">
|
|
66
|
-
|
|
67
|
-
<
|
|
68
|
-
{
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
isActive && 'active',
|
|
88
|
-
!readonly && [
|
|
89
|
-
isPreviousStep && 'previous',
|
|
90
|
-
isValid && 'valid',
|
|
91
|
-
isInvalid && 'invalid',
|
|
92
|
-
disabled && 'disabled'
|
|
93
|
-
]
|
|
94
|
-
]}
|
|
95
|
-
>
|
|
96
|
-
<div class="time-line">
|
|
97
|
-
<span class="circle spi-text-semibold-1">
|
|
98
|
-
{circleContent()}
|
|
99
|
-
</span>
|
|
100
|
-
<span class="line"></span>
|
|
101
|
-
</div>
|
|
102
|
-
<button
|
|
103
|
-
type="button"
|
|
104
|
-
class="details"
|
|
105
|
-
disabled={disabled || readonly}
|
|
106
|
-
onclick={() => (currentStep = stepIndex)}
|
|
107
|
-
>
|
|
108
|
-
<h2 class="spi-text-semibold-3">{step.title}</h2>
|
|
109
|
-
{#if step.description}
|
|
110
|
-
<p class="spi-text-regular-1">{step.description}</p>
|
|
111
|
-
{/if}
|
|
112
|
-
</button>
|
|
113
|
-
</li>
|
|
114
|
-
{/each}
|
|
115
|
-
</ol>
|
|
116
|
-
<article class="progress-wizard-content">
|
|
117
|
-
{#if allStepsDisabled}
|
|
118
|
-
<ErrorPage status={403} title="All steps disabled" />
|
|
119
|
-
{:else}
|
|
120
|
-
{@render content()}
|
|
121
|
-
{/if}
|
|
122
|
-
</article>
|
|
123
|
-
</section>
|
|
124
|
-
<section class="progress-wizard-footer">
|
|
125
|
-
<Button type="button" variant="outline-none" onclick={oncancel}>Cancel</Button>
|
|
126
|
-
|
|
127
|
-
<div class="actions">
|
|
128
|
-
{#if !allStepsDisabled}
|
|
129
|
-
{#if !readonly}
|
|
130
|
-
<Button
|
|
131
|
-
type="button"
|
|
132
|
-
variant="secondary"
|
|
133
|
-
disabled={currentStep === firstActiveStep}
|
|
134
|
-
onclick={onclickBack}>Back</Button
|
|
135
|
-
>
|
|
136
|
-
|
|
137
|
-
{#if currentStep < lastActiveStep}
|
|
138
|
-
<Button type="button" variant="primary" onclick={onclickNext}>Next</Button>
|
|
139
|
-
{/if}
|
|
140
|
-
{/if}
|
|
141
|
-
|
|
142
|
-
{@render additionalButtons(lastActiveStep)}
|
|
143
|
-
{/if}
|
|
144
|
-
</div>
|
|
145
|
-
</section>
|
|
89
|
+
{#if props.orientation === 'horizontal'}
|
|
90
|
+
<ProgressWizardHorizontal
|
|
91
|
+
{allStepsDisabled}
|
|
92
|
+
{firstActiveStep}
|
|
93
|
+
{lastActiveStep}
|
|
94
|
+
onclickback={onclickBack}
|
|
95
|
+
onclicknext={onclickNext}
|
|
96
|
+
{content}
|
|
97
|
+
/>
|
|
98
|
+
{:else}
|
|
99
|
+
<ProgressWizardVertical
|
|
100
|
+
{allStepsDisabled}
|
|
101
|
+
{firstActiveStep}
|
|
102
|
+
{lastActiveStep}
|
|
103
|
+
additionalButtons={props.additionalButtons}
|
|
104
|
+
oncancel={props.oncancel}
|
|
105
|
+
onclickback={onclickBack}
|
|
106
|
+
onclicknext={onclickNext}
|
|
107
|
+
{content}
|
|
108
|
+
/>
|
|
109
|
+
{/if}
|
|
146
110
|
</div>
|
|
147
111
|
|
|
148
112
|
<style>
|
|
@@ -156,188 +120,4 @@
|
|
|
156
120
|
flex-direction: column;
|
|
157
121
|
width: 100%;
|
|
158
122
|
}
|
|
159
|
-
|
|
160
|
-
.progress-wizard-container {
|
|
161
|
-
display: flex;
|
|
162
|
-
flex: 1;
|
|
163
|
-
}
|
|
164
|
-
|
|
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);
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
.progress-wizard-step {
|
|
174
|
-
display: grid;
|
|
175
|
-
grid-template-columns: auto 1fr;
|
|
176
|
-
max-height: 70px;
|
|
177
|
-
padding: var(--spi-size-4) var(--spi-size-6);
|
|
178
|
-
gap: var(--spi-size-2);
|
|
179
|
-
align-items: center;
|
|
180
|
-
border: none;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
.time-line {
|
|
184
|
-
position: relative;
|
|
185
|
-
display: flex;
|
|
186
|
-
flex-direction: column;
|
|
187
|
-
align-items: center;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
.circle {
|
|
191
|
-
display: flex;
|
|
192
|
-
width: var(--circle-size);
|
|
193
|
-
height: var(--circle-size);
|
|
194
|
-
align-items: center;
|
|
195
|
-
justify-content: center;
|
|
196
|
-
border-radius: 50%;
|
|
197
|
-
background: var(--spi-color-primary-lighter);
|
|
198
|
-
color: var(--spi-color-primary-base);
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
.line {
|
|
202
|
-
position: absolute;
|
|
203
|
-
top: var(--circle-size);
|
|
204
|
-
width: 1px;
|
|
205
|
-
height: 50px;
|
|
206
|
-
background: var(--spi-color-border-default);
|
|
207
|
-
transition: background var(--spi-duration-slower) var(--spi-ease-default);
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
.progress-wizard-step:last-child .time-line .line {
|
|
211
|
-
display: none;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
.details {
|
|
215
|
-
padding: var(--spi-size-1) var(--spi-size-2);
|
|
216
|
-
text-align: left;
|
|
217
|
-
border: none;
|
|
218
|
-
border-radius: var(--spi-rounded-lg);
|
|
219
|
-
background: transparent;
|
|
220
|
-
cursor: pointer;
|
|
221
|
-
|
|
222
|
-
h2 {
|
|
223
|
-
color: var(--spi-color-text-primary);
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
p {
|
|
227
|
-
word-break: keep-all;
|
|
228
|
-
color: var(--spi-color-text-muted);
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
.details:hover {
|
|
233
|
-
background: var(--spi-color-surface-subtle);
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
.details:focus-visible:not(:disabled) {
|
|
237
|
-
background: var(--spi-color-surface-subtle);
|
|
238
|
-
box-shadow: 0 0 0 var(--spi-border-2) var(--spi-color-focus-ring);
|
|
239
|
-
outline: none;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
.progress-wizard-content {
|
|
243
|
-
flex: 1;
|
|
244
|
-
padding: var(--spi-size-6);
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
.progress-wizard-footer {
|
|
248
|
-
display: flex;
|
|
249
|
-
padding: var(--spi-size-6);
|
|
250
|
-
border-top: var(--border-wizard);
|
|
251
|
-
|
|
252
|
-
.actions {
|
|
253
|
-
display: flex;
|
|
254
|
-
gap: var(--spi-size-3);
|
|
255
|
-
margin-left: auto;
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
.progress-wizard-step.active {
|
|
260
|
-
.time-line .circle {
|
|
261
|
-
border: var(--border-circle);
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
.details {
|
|
265
|
-
box-shadow: none;
|
|
266
|
-
background: transparent;
|
|
267
|
-
|
|
268
|
-
h2,
|
|
269
|
-
p {
|
|
270
|
-
color: var(--spi-color-primary-base);
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
.progress-wizard-steps:is(.readonly) {
|
|
276
|
-
.progress-wizard-step:not(.active) {
|
|
277
|
-
.line {
|
|
278
|
-
background: var(--spi-color-border-default);
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
.circle {
|
|
282
|
-
border: var(--border-readonly);
|
|
283
|
-
background: var(--spi-color-disabled-bg);
|
|
284
|
-
color: var(--spi-color-text-muted);
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
.details {
|
|
288
|
-
h2 {
|
|
289
|
-
color: var(--spi-color-text-muted);
|
|
290
|
-
}
|
|
291
|
-
p {
|
|
292
|
-
color: var(--spi-color-text-disabled);
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
.details:hover {
|
|
297
|
-
background: transparent;
|
|
298
|
-
cursor: not-allowed;
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
.progress-wizard-steps:is(.editing-mode) {
|
|
304
|
-
.progress-wizard-step.previous .time-line .line {
|
|
305
|
-
background: var(--spi-color-primary-base);
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
.progress-wizard-step.previous.valid .time-line .circle {
|
|
309
|
-
color: var(--spi-color-text-inverse);
|
|
310
|
-
background: var(--spi-color-primary-base);
|
|
311
|
-
border: var(--border-circle);
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
.progress-wizard-step.previous.invalid .time-line .circle {
|
|
315
|
-
color: var(--spi-color-text-danger);
|
|
316
|
-
background: var(--spi-color-danger-lighter);
|
|
317
|
-
border: var(--spi-border-2) solid var(--spi-color-border-danger);
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
.progress-wizard-step:is(.disabled, .previous.disabled) {
|
|
321
|
-
.details {
|
|
322
|
-
h2 {
|
|
323
|
-
color: var(--spi-color-text-muted);
|
|
324
|
-
}
|
|
325
|
-
p {
|
|
326
|
-
color: var(--spi-color-text-disabled);
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
.details:hover {
|
|
330
|
-
background: transparent;
|
|
331
|
-
cursor: not-allowed;
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
.time-line {
|
|
335
|
-
.circle {
|
|
336
|
-
color: var(--spi-color-text-muted);
|
|
337
|
-
background: var(--spi-color-disabled-bg);
|
|
338
|
-
border: var(--border-readonly);
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
123
|
</style>
|
|
@@ -1,14 +1,23 @@
|
|
|
1
1
|
import { type Snippet } from 'svelte';
|
|
2
2
|
import { type ProgressWizardStep } from '../../index.js';
|
|
3
|
-
interface
|
|
3
|
+
interface BaseProps {
|
|
4
4
|
steps: ProgressWizardStep[];
|
|
5
5
|
currentStep: number;
|
|
6
6
|
readonly?: boolean;
|
|
7
7
|
initialStep?: number;
|
|
8
8
|
content: Snippet;
|
|
9
|
+
}
|
|
10
|
+
interface HorizontalProps extends BaseProps {
|
|
11
|
+
orientation: 'horizontal';
|
|
12
|
+
additionalButtons?: never;
|
|
13
|
+
oncancel?: never;
|
|
14
|
+
}
|
|
15
|
+
interface VerticalProps extends BaseProps {
|
|
16
|
+
orientation?: 'vertical';
|
|
9
17
|
additionalButtons: Snippet<[lastActiveStep: number]>;
|
|
10
18
|
oncancel: VoidFunction;
|
|
11
19
|
}
|
|
20
|
+
type Props = VerticalProps | HorizontalProps;
|
|
12
21
|
declare const ProgressWizard: import("svelte").Component<Props, {}, "currentStep">;
|
|
13
22
|
type ProgressWizard = ReturnType<typeof ProgressWizard>;
|
|
14
23
|
export default ProgressWizard;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Button, Card, ErrorPage } from '../../index.js';
|
|
3
|
+
import { getWizardContext } from './context.js';
|
|
4
|
+
import ProgressWizardStep from './ProgressWizardStep.svelte';
|
|
5
|
+
import type { BaseProgressWizardProps } from './types.js';
|
|
6
|
+
|
|
7
|
+
let {
|
|
8
|
+
allStepsDisabled,
|
|
9
|
+
firstActiveStep,
|
|
10
|
+
lastActiveStep,
|
|
11
|
+
onclickback,
|
|
12
|
+
onclicknext,
|
|
13
|
+
content
|
|
14
|
+
}: BaseProgressWizardProps = $props();
|
|
15
|
+
|
|
16
|
+
const wizard = getWizardContext();
|
|
17
|
+
|
|
18
|
+
const readonly = $derived<boolean>(wizard.readonly);
|
|
19
|
+
const currentStep = $derived<number>(wizard.currentStep);
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<section class="progress-wizard-container">
|
|
23
|
+
<Card>
|
|
24
|
+
{#if !allStepsDisabled}
|
|
25
|
+
{#if !readonly}
|
|
26
|
+
<Button
|
|
27
|
+
type="button"
|
|
28
|
+
variant="outline"
|
|
29
|
+
disabled={currentStep === firstActiveStep}
|
|
30
|
+
onclick={onclickback}>Back</Button
|
|
31
|
+
>
|
|
32
|
+
{/if}
|
|
33
|
+
{/if}
|
|
34
|
+
|
|
35
|
+
<ProgressWizardStep />
|
|
36
|
+
|
|
37
|
+
{#if !allStepsDisabled}
|
|
38
|
+
{#if !readonly}
|
|
39
|
+
{#if currentStep < lastActiveStep}
|
|
40
|
+
<Button type="button" variant="outline" onclick={onclicknext}>Next</Button>
|
|
41
|
+
{/if}
|
|
42
|
+
{/if}
|
|
43
|
+
{/if}
|
|
44
|
+
</Card>
|
|
45
|
+
<Card>
|
|
46
|
+
{#if allStepsDisabled}
|
|
47
|
+
<ErrorPage status={403} title="All steps disabled" />
|
|
48
|
+
{:else}
|
|
49
|
+
{@render content()}
|
|
50
|
+
{/if}
|
|
51
|
+
</Card>
|
|
52
|
+
</section>
|
|
53
|
+
|
|
54
|
+
<style>
|
|
55
|
+
.progress-wizard-container {
|
|
56
|
+
display: flex;
|
|
57
|
+
flex-direction: column;
|
|
58
|
+
gap: var(--spi-size-4);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.progress-wizard-container > :global(.card):first-child {
|
|
62
|
+
display: flex;
|
|
63
|
+
align-items: center;
|
|
64
|
+
gap: var(--spi-size-8);
|
|
65
|
+
}
|
|
66
|
+
</style>
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { BaseProgressWizardProps } from './types.js';
|
|
2
|
+
declare const ProgressWizardHorizontal: import("svelte").Component<BaseProgressWizardProps, {}, "">;
|
|
3
|
+
type ProgressWizardHorizontal = ReturnType<typeof ProgressWizardHorizontal>;
|
|
4
|
+
export default ProgressWizardHorizontal;
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { getWizardContext } from './context.js';
|
|
3
|
+
import type { ProgressWizardStep } from './types.js';
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
isVertical?: boolean;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
let { isVertical = false }: Props = $props();
|
|
10
|
+
|
|
11
|
+
const wizard = getWizardContext();
|
|
12
|
+
|
|
13
|
+
const readonly = $derived<boolean>(wizard.readonly);
|
|
14
|
+
const steps = $derived<ProgressWizardStep[]>(wizard.steps);
|
|
15
|
+
const currentStep = $derived<number>(wizard.currentStep);
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<ol
|
|
19
|
+
class={[
|
|
20
|
+
'progress-wizard-steps',
|
|
21
|
+
isVertical ? 'vertical' : 'horizontal',
|
|
22
|
+
readonly ? 'readonly' : 'editing-mode'
|
|
23
|
+
]}
|
|
24
|
+
>
|
|
25
|
+
{#each steps as step, index (index)}
|
|
26
|
+
{@const stepIndex = index + 1}
|
|
27
|
+
{@const isActive = stepIndex === currentStep}
|
|
28
|
+
{@const isPreviousStep = currentStep > stepIndex}
|
|
29
|
+
{@const isValid = isPreviousStep && step.isValid}
|
|
30
|
+
{@const isInvalid = isPreviousStep && !step.isValid}
|
|
31
|
+
{@const disabled = step.disabled}
|
|
32
|
+
|
|
33
|
+
{@const circleContent = (): string => {
|
|
34
|
+
if (isActive) return stepIndex.toString();
|
|
35
|
+
if (readonly || disabled) return 'ー';
|
|
36
|
+
if (isValid) return '✔';
|
|
37
|
+
if (isInvalid) return '✖';
|
|
38
|
+
return stepIndex.toString();
|
|
39
|
+
}}
|
|
40
|
+
|
|
41
|
+
<li
|
|
42
|
+
class={[
|
|
43
|
+
'progress-wizard-step',
|
|
44
|
+
isVertical && 'vertical',
|
|
45
|
+
isActive && 'active',
|
|
46
|
+
!readonly && [
|
|
47
|
+
isPreviousStep && 'previous',
|
|
48
|
+
isValid && 'valid',
|
|
49
|
+
isInvalid && 'invalid',
|
|
50
|
+
disabled && 'disabled'
|
|
51
|
+
]
|
|
52
|
+
]}
|
|
53
|
+
>
|
|
54
|
+
<div class="time-line">
|
|
55
|
+
<span class="circle spi-text-semibold-1">
|
|
56
|
+
{circleContent()}
|
|
57
|
+
</span>
|
|
58
|
+
{#if isVertical}
|
|
59
|
+
<span class="line"></span>
|
|
60
|
+
{/if}
|
|
61
|
+
</div>
|
|
62
|
+
<button
|
|
63
|
+
type="button"
|
|
64
|
+
class="details"
|
|
65
|
+
disabled={disabled || readonly}
|
|
66
|
+
onclick={() => wizard.setCurrentStep(stepIndex)}
|
|
67
|
+
>
|
|
68
|
+
<h2 class="spi-text-semibold-3">{step.title}</h2>
|
|
69
|
+
{#if step.description}
|
|
70
|
+
<p class="spi-text-regular-1">{step.description}</p>
|
|
71
|
+
{/if}
|
|
72
|
+
</button>
|
|
73
|
+
</li>
|
|
74
|
+
{/each}
|
|
75
|
+
</ol>
|
|
76
|
+
|
|
77
|
+
<style>
|
|
78
|
+
.progress-wizard-steps {
|
|
79
|
+
display: flex;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.progress-wizard-steps.vertical {
|
|
83
|
+
flex-direction: column;
|
|
84
|
+
width: fit-content;
|
|
85
|
+
max-width: 250px;
|
|
86
|
+
border-right: var(--border-wizard);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.progress-wizard-steps.horizontal {
|
|
90
|
+
flex-direction: row;
|
|
91
|
+
width: 100%;
|
|
92
|
+
gap: var(--spi-size-8);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.progress-wizard-step {
|
|
96
|
+
display: grid;
|
|
97
|
+
grid-template-columns: auto 1fr;
|
|
98
|
+
max-height: 70px;
|
|
99
|
+
gap: var(--spi-size-2);
|
|
100
|
+
align-items: center;
|
|
101
|
+
border: none;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.progress-wizard-step.vertical {
|
|
105
|
+
padding: var(--spi-size-4) var(--spi-size-6);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.time-line {
|
|
109
|
+
position: relative;
|
|
110
|
+
display: flex;
|
|
111
|
+
flex-direction: column;
|
|
112
|
+
align-items: center;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.circle {
|
|
116
|
+
display: flex;
|
|
117
|
+
width: var(--circle-size);
|
|
118
|
+
height: var(--circle-size);
|
|
119
|
+
align-items: center;
|
|
120
|
+
justify-content: center;
|
|
121
|
+
border-radius: 50%;
|
|
122
|
+
background: var(--spi-color-primary-lighter);
|
|
123
|
+
color: var(--spi-color-primary-base);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.line {
|
|
127
|
+
position: absolute;
|
|
128
|
+
top: var(--circle-size);
|
|
129
|
+
width: 1px;
|
|
130
|
+
height: 50px;
|
|
131
|
+
background: var(--spi-color-border-default);
|
|
132
|
+
transition: background var(--spi-duration-slower) var(--spi-ease-default);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.progress-wizard-step:last-child .time-line .line {
|
|
136
|
+
display: none;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.details {
|
|
140
|
+
padding: var(--spi-size-1) var(--spi-size-2);
|
|
141
|
+
text-align: left;
|
|
142
|
+
border: none;
|
|
143
|
+
border-radius: var(--spi-rounded-lg);
|
|
144
|
+
background: transparent;
|
|
145
|
+
cursor: pointer;
|
|
146
|
+
|
|
147
|
+
h2 {
|
|
148
|
+
color: var(--spi-color-text-primary);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
p {
|
|
152
|
+
word-break: keep-all;
|
|
153
|
+
color: var(--spi-color-text-muted);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
.details:hover {
|
|
158
|
+
background: var(--spi-color-surface-subtle);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.details:focus-visible:not(:disabled) {
|
|
162
|
+
background: var(--spi-color-surface-subtle);
|
|
163
|
+
box-shadow: 0 0 0 var(--spi-border-2) var(--spi-color-focus-ring);
|
|
164
|
+
outline: none;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.progress-wizard-step.active {
|
|
168
|
+
.time-line .circle {
|
|
169
|
+
border: var(--border-circle);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.details {
|
|
173
|
+
box-shadow: none;
|
|
174
|
+
background: transparent;
|
|
175
|
+
|
|
176
|
+
h2,
|
|
177
|
+
p {
|
|
178
|
+
color: var(--spi-color-primary-base);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
.progress-wizard-steps:is(.readonly) {
|
|
184
|
+
.progress-wizard-step:not(.active) {
|
|
185
|
+
.line {
|
|
186
|
+
background: var(--spi-color-border-default);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.circle {
|
|
190
|
+
border: var(--border-readonly);
|
|
191
|
+
background: var(--spi-color-disabled-bg);
|
|
192
|
+
color: var(--spi-color-text-muted);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.details {
|
|
196
|
+
h2 {
|
|
197
|
+
color: var(--spi-color-text-muted);
|
|
198
|
+
}
|
|
199
|
+
p {
|
|
200
|
+
color: var(--spi-color-text-disabled);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.details:hover {
|
|
205
|
+
background: transparent;
|
|
206
|
+
cursor: not-allowed;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
.progress-wizard-steps:is(.editing-mode) {
|
|
212
|
+
.progress-wizard-step.previous .time-line .line {
|
|
213
|
+
background: var(--spi-color-primary-base);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
.progress-wizard-step.previous.valid .time-line .circle {
|
|
217
|
+
color: var(--spi-color-text-inverse);
|
|
218
|
+
background: var(--spi-color-primary-base);
|
|
219
|
+
border: var(--border-circle);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.progress-wizard-step.previous.invalid .time-line .circle {
|
|
223
|
+
color: var(--spi-color-text-danger);
|
|
224
|
+
background: var(--spi-color-danger-lighter);
|
|
225
|
+
border: var(--spi-border-2) solid var(--spi-color-border-danger);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
.progress-wizard-step:is(.disabled, .previous.disabled) {
|
|
229
|
+
.details {
|
|
230
|
+
h2 {
|
|
231
|
+
color: var(--spi-color-text-muted);
|
|
232
|
+
}
|
|
233
|
+
p {
|
|
234
|
+
color: var(--spi-color-text-disabled);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
.details:hover {
|
|
238
|
+
background: transparent;
|
|
239
|
+
cursor: not-allowed;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
.time-line {
|
|
243
|
+
.circle {
|
|
244
|
+
color: var(--spi-color-text-muted);
|
|
245
|
+
background: var(--spi-color-disabled-bg);
|
|
246
|
+
border: var(--border-readonly);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
</style>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ProgressWizardStep } from './types.js';
|
|
2
|
+
interface Props {
|
|
3
|
+
isVertical?: boolean;
|
|
4
|
+
}
|
|
5
|
+
declare const ProgressWizardStep: import("svelte").Component<Props, {}, "">;
|
|
6
|
+
type ProgressWizardStep = ReturnType<typeof ProgressWizardStep>;
|
|
7
|
+
export default ProgressWizardStep;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { type Snippet } from 'svelte';
|
|
3
|
+
|
|
4
|
+
import { Button, ErrorPage } from '../../index.js';
|
|
5
|
+
import { getWizardContext } from './context.js';
|
|
6
|
+
import ProgressWizardStep from './ProgressWizardStep.svelte';
|
|
7
|
+
import type { BaseProgressWizardProps } from './types.js';
|
|
8
|
+
|
|
9
|
+
interface Props extends BaseProgressWizardProps {
|
|
10
|
+
additionalButtons: Snippet<[lastActiveStep: number]>;
|
|
11
|
+
oncancel: VoidFunction;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
let {
|
|
15
|
+
allStepsDisabled,
|
|
16
|
+
firstActiveStep,
|
|
17
|
+
lastActiveStep,
|
|
18
|
+
additionalButtons,
|
|
19
|
+
oncancel,
|
|
20
|
+
onclickback,
|
|
21
|
+
onclicknext,
|
|
22
|
+
content
|
|
23
|
+
}: Props = $props();
|
|
24
|
+
|
|
25
|
+
const wizard = getWizardContext();
|
|
26
|
+
|
|
27
|
+
const readonly = $derived<boolean>(wizard.readonly);
|
|
28
|
+
const currentStep = $derived<number>(wizard.currentStep);
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<section class="progress-wizard-container">
|
|
32
|
+
<ProgressWizardStep isVertical />
|
|
33
|
+
|
|
34
|
+
<article class="progress-wizard-content">
|
|
35
|
+
{#if allStepsDisabled}
|
|
36
|
+
<ErrorPage status={403} title="All steps disabled" />
|
|
37
|
+
{:else}
|
|
38
|
+
{@render content()}
|
|
39
|
+
{/if}
|
|
40
|
+
</article>
|
|
41
|
+
</section>
|
|
42
|
+
|
|
43
|
+
<section class="progress-wizard-footer">
|
|
44
|
+
<Button type="button" variant="outline-none" onclick={oncancel}>Cancel</Button>
|
|
45
|
+
|
|
46
|
+
<div class="actions">
|
|
47
|
+
{#if !allStepsDisabled}
|
|
48
|
+
{#if !readonly}
|
|
49
|
+
<Button
|
|
50
|
+
type="button"
|
|
51
|
+
variant="secondary"
|
|
52
|
+
disabled={currentStep === firstActiveStep}
|
|
53
|
+
onclick={onclickback}>Back</Button
|
|
54
|
+
>
|
|
55
|
+
|
|
56
|
+
{#if currentStep < lastActiveStep}
|
|
57
|
+
<Button type="button" variant="primary" onclick={onclicknext}>Next</Button>
|
|
58
|
+
{/if}
|
|
59
|
+
{/if}
|
|
60
|
+
|
|
61
|
+
{@render additionalButtons(lastActiveStep)}
|
|
62
|
+
{/if}
|
|
63
|
+
</div>
|
|
64
|
+
</section>
|
|
65
|
+
|
|
66
|
+
<style>
|
|
67
|
+
.progress-wizard-container {
|
|
68
|
+
display: flex;
|
|
69
|
+
flex: 1;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.progress-wizard-content {
|
|
73
|
+
flex: 1;
|
|
74
|
+
padding: var(--spi-size-6);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.progress-wizard-footer {
|
|
78
|
+
display: flex;
|
|
79
|
+
padding: var(--spi-size-6);
|
|
80
|
+
border-top: var(--border-wizard);
|
|
81
|
+
|
|
82
|
+
.actions {
|
|
83
|
+
display: flex;
|
|
84
|
+
gap: var(--spi-size-3);
|
|
85
|
+
margin-left: auto;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
</style>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type Snippet } from 'svelte';
|
|
2
|
+
import type { BaseProgressWizardProps } from './types.js';
|
|
3
|
+
interface Props extends BaseProgressWizardProps {
|
|
4
|
+
additionalButtons: Snippet<[lastActiveStep: number]>;
|
|
5
|
+
oncancel: VoidFunction;
|
|
6
|
+
}
|
|
7
|
+
declare const ProgressWizardVertical: import("svelte").Component<Props, {}, "">;
|
|
8
|
+
type ProgressWizardVertical = ReturnType<typeof ProgressWizardVertical>;
|
|
9
|
+
export default ProgressWizardVertical;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type Writable } from 'svelte/store';
|
|
2
|
-
import type { ProgressWizardStep } from './types.js';
|
|
2
|
+
import type { ProgressWizardContext, ProgressWizardContextAccessors, ProgressWizardStep } from './types.js';
|
|
3
3
|
export declare const setProgressWizardStepsContext: (steps: ProgressWizardStep[]) => Writable<{
|
|
4
4
|
title: string;
|
|
5
5
|
description?: string;
|
|
@@ -7,3 +7,5 @@ export declare const setProgressWizardStepsContext: (steps: ProgressWizardStep[]
|
|
|
7
7
|
disabled: boolean;
|
|
8
8
|
}[]>;
|
|
9
9
|
export declare const getProgressWizardContext: () => Writable<ProgressWizardStep[]>;
|
|
10
|
+
export declare const setWizardContext: (accessors: ProgressWizardContextAccessors) => ProgressWizardContext;
|
|
11
|
+
export declare const getWizardContext: () => ProgressWizardContext;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { getContext, setContext } from 'svelte';
|
|
2
2
|
import { writable } from 'svelte/store';
|
|
3
3
|
const stepsKey = Symbol('steps');
|
|
4
|
+
const WIZARD_CONTEXT_KEY = Symbol('progressWizard');
|
|
4
5
|
export const setProgressWizardStepsContext = (steps) => {
|
|
5
6
|
const stepsContext = writable(steps.map((step) => ({ ...step })));
|
|
6
7
|
setContext(stepsKey, stepsContext);
|
|
@@ -9,3 +10,16 @@ export const setProgressWizardStepsContext = (steps) => {
|
|
|
9
10
|
export const getProgressWizardContext = () => {
|
|
10
11
|
return getContext(stepsKey);
|
|
11
12
|
};
|
|
13
|
+
export const setWizardContext = (accessors) => setContext(WIZARD_CONTEXT_KEY, {
|
|
14
|
+
get currentStep() {
|
|
15
|
+
return accessors.getCurrentStep();
|
|
16
|
+
},
|
|
17
|
+
get readonly() {
|
|
18
|
+
return accessors.getReadonly();
|
|
19
|
+
},
|
|
20
|
+
get steps() {
|
|
21
|
+
return accessors.getSteps();
|
|
22
|
+
},
|
|
23
|
+
setCurrentStep: accessors.setCurrentStep
|
|
24
|
+
});
|
|
25
|
+
export const getWizardContext = () => getContext(WIZARD_CONTEXT_KEY);
|
|
@@ -1,6 +1,27 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
export interface BaseProgressWizardProps {
|
|
3
|
+
allStepsDisabled: boolean;
|
|
4
|
+
firstActiveStep: number;
|
|
5
|
+
lastActiveStep: number;
|
|
6
|
+
onclickback: VoidFunction;
|
|
7
|
+
onclicknext: VoidFunction;
|
|
8
|
+
content: Snippet;
|
|
9
|
+
}
|
|
1
10
|
export type ProgressWizardStep = {
|
|
2
11
|
title: string;
|
|
3
12
|
description?: string;
|
|
4
13
|
isValid: boolean;
|
|
5
14
|
disabled: boolean;
|
|
6
15
|
};
|
|
16
|
+
export type ProgressWizardContext = {
|
|
17
|
+
steps: ProgressWizardStep[];
|
|
18
|
+
readonly: boolean;
|
|
19
|
+
currentStep: number;
|
|
20
|
+
setCurrentStep: (step: number) => void;
|
|
21
|
+
};
|
|
22
|
+
export type ProgressWizardContextAccessors = {
|
|
23
|
+
getSteps: () => ProgressWizardStep[];
|
|
24
|
+
getReadonly: () => boolean;
|
|
25
|
+
getCurrentStep: () => number;
|
|
26
|
+
setCurrentStep: (step: number) => void;
|
|
27
|
+
};
|
|
@@ -5,9 +5,10 @@
|
|
|
5
5
|
interface Props {
|
|
6
6
|
bodyRows: Row<T>[];
|
|
7
7
|
enableChecked?: boolean;
|
|
8
|
+
disabledRows: T[];
|
|
8
9
|
}
|
|
9
10
|
|
|
10
|
-
let { bodyRows, enableChecked = false }: Props = $props();
|
|
11
|
+
let { bodyRows, enableChecked = false, disabledRows }: Props = $props();
|
|
11
12
|
|
|
12
13
|
const CLICKABLE_TAGS = ['td', 'span', 'p'];
|
|
13
14
|
|
|
@@ -18,6 +19,8 @@
|
|
|
18
19
|
row.toggleSelected();
|
|
19
20
|
}
|
|
20
21
|
};
|
|
22
|
+
|
|
23
|
+
const isDisabledRow = (row: T) => disabledRows.includes(row);
|
|
21
24
|
</script>
|
|
22
25
|
|
|
23
26
|
<tbody class="table-body">
|
|
@@ -27,9 +30,12 @@
|
|
|
27
30
|
class={[
|
|
28
31
|
'table-row',
|
|
29
32
|
row.getIsSelected() && 'table-row--selected',
|
|
30
|
-
enableChecked && 'table-row--clickable'
|
|
33
|
+
enableChecked && 'table-row--clickable',
|
|
34
|
+
isDisabledRow(row.original) && 'cursor-not-allowed'
|
|
31
35
|
]}
|
|
32
|
-
onclick={enableChecked
|
|
36
|
+
onclick={enableChecked && !isDisabledRow(row.original)
|
|
37
|
+
? (event) => handleRowClick(row, event.target)
|
|
38
|
+
: undefined}
|
|
33
39
|
>
|
|
34
40
|
{#each row.getVisibleCells() as cell (cell.id)}
|
|
35
41
|
{@const alignColumn = cell.column.columnDef.meta?.alignColumn}
|
|
@@ -98,4 +104,8 @@
|
|
|
98
104
|
.table-cell--right {
|
|
99
105
|
text-align: right;
|
|
100
106
|
}
|
|
107
|
+
|
|
108
|
+
.cursor-not-allowed {
|
|
109
|
+
cursor: not-allowed;
|
|
110
|
+
}
|
|
101
111
|
</style>
|
|
@@ -43,12 +43,11 @@
|
|
|
43
43
|
isValidPageSize
|
|
44
44
|
} from './utils.js';
|
|
45
45
|
|
|
46
|
-
interface
|
|
46
|
+
interface BaseProps<T> {
|
|
47
47
|
columns: ColumnDef<T, any>[];
|
|
48
48
|
isLoading?: boolean;
|
|
49
49
|
data?: T[];
|
|
50
50
|
minPageSize?: boolean;
|
|
51
|
-
enableChecked?: boolean;
|
|
52
51
|
keepVisibleBulkActions?: boolean;
|
|
53
52
|
enableExportExcel?: boolean;
|
|
54
53
|
enableGlobalSearch?: boolean;
|
|
@@ -68,12 +67,34 @@
|
|
|
68
67
|
onprevpage?: (pageSize: number, pageNumber: number) => void;
|
|
69
68
|
}
|
|
70
69
|
|
|
70
|
+
interface TableWithCheckbox<T> extends BaseProps<T> {
|
|
71
|
+
enableChecked: true;
|
|
72
|
+
preselectedRows?: T[];
|
|
73
|
+
disabledRows?: T[];
|
|
74
|
+
onselectionchange?: (selectedRows: T[]) => void;
|
|
75
|
+
onclearselection?: (clearSelection: VoidFunction) => void;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
interface TableWithoutCheckbox<T> extends BaseProps<T> {
|
|
79
|
+
enableChecked?: false;
|
|
80
|
+
preselectedRows?: never;
|
|
81
|
+
disabledRows?: never;
|
|
82
|
+
onselectionchange?: never;
|
|
83
|
+
onclearselection?: never;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
type Props<T> = TableWithCheckbox<T> | TableWithoutCheckbox<T>;
|
|
87
|
+
|
|
71
88
|
let {
|
|
72
89
|
columns = [],
|
|
73
90
|
isLoading = false,
|
|
74
91
|
data = [],
|
|
75
92
|
minPageSize = false,
|
|
76
93
|
enableChecked = false,
|
|
94
|
+
preselectedRows = [],
|
|
95
|
+
disabledRows = [],
|
|
96
|
+
onselectionchange,
|
|
97
|
+
onclearselection,
|
|
77
98
|
keepVisibleBulkActions = false,
|
|
78
99
|
enableExportExcel = false,
|
|
79
100
|
enableGlobalSearch = true,
|
|
@@ -94,26 +115,41 @@
|
|
|
94
115
|
onprevpage,
|
|
95
116
|
header,
|
|
96
117
|
bulkActions
|
|
97
|
-
}: Props = $props();
|
|
118
|
+
}: Props<T> = $props();
|
|
119
|
+
|
|
120
|
+
const tableManualPagination = serverSide ? setPaginationTableContext() : undefined;
|
|
98
121
|
|
|
99
122
|
let globalFilter = $state<string>('');
|
|
100
123
|
let sorting = $state<SortingState>([]);
|
|
101
124
|
let columnFilters = $state<ColumnFiltersState>([]);
|
|
102
|
-
let rowSelection = $state<RowSelectionState>({});
|
|
103
125
|
let expanded = $state<ExpandedState>({});
|
|
104
126
|
let columnVisibility = $state<VisibilityState>(getInitialColumnVisibility());
|
|
105
127
|
let paginationState = $state<PaginationState>(getInitialPaginationState());
|
|
128
|
+
let rowSelection = $state<RowSelectionState>();
|
|
129
|
+
|
|
106
130
|
let tableData = $derived(data);
|
|
107
|
-
const tableManualPagination = serverSide ? setPaginationTableContext() : undefined;
|
|
108
131
|
const hasData = $derived(data.length > 0);
|
|
109
132
|
|
|
133
|
+
const selectedRowIds = $derived.by<RowSelectionState>(() => {
|
|
134
|
+
if (rowSelection !== undefined) return rowSelection;
|
|
135
|
+
if (!enableChecked || !preselectedRows?.length) return {};
|
|
136
|
+
|
|
137
|
+
const selectedRowIds: RowSelectionState = {};
|
|
138
|
+
|
|
139
|
+
table.getRowModel().rows.forEach((row) => {
|
|
140
|
+
if (preselectedRows.includes(row.original)) selectedRowIds[row.id] = true;
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
return selectedRowIds;
|
|
144
|
+
});
|
|
145
|
+
|
|
110
146
|
const tableColumns = $derived.by(() => {
|
|
111
147
|
if (!enableChecked) return columns;
|
|
112
148
|
|
|
113
149
|
const checkedColumnExists = columns.some((column) => column.id === 'checked');
|
|
114
150
|
if (checkedColumnExists) return columns;
|
|
115
151
|
|
|
116
|
-
const checkedColumn = createCheckedColumn<T>();
|
|
152
|
+
const checkedColumn = createCheckedColumn<T>(disabledRows);
|
|
117
153
|
return [checkedColumn, ...columns];
|
|
118
154
|
});
|
|
119
155
|
|
|
@@ -135,7 +171,7 @@
|
|
|
135
171
|
return columnFilters;
|
|
136
172
|
},
|
|
137
173
|
get rowSelection() {
|
|
138
|
-
return
|
|
174
|
+
return selectedRowIds;
|
|
139
175
|
},
|
|
140
176
|
get globalFilter() {
|
|
141
177
|
return globalFilter;
|
|
@@ -157,7 +193,7 @@
|
|
|
157
193
|
columnVisibility = updater instanceof Function ? updater(columnVisibility) : updater;
|
|
158
194
|
},
|
|
159
195
|
onRowSelectionChange: (updater: Updater<RowSelectionState>) => {
|
|
160
|
-
rowSelection = updater instanceof Function ? updater(
|
|
196
|
+
rowSelection = updater instanceof Function ? updater(selectedRowIds) : updater;
|
|
161
197
|
},
|
|
162
198
|
onColumnFiltersChange: (updater: Updater<ColumnFiltersState>) => {
|
|
163
199
|
columnFilters = updater instanceof Function ? updater(columnFilters) : updater;
|
|
@@ -264,6 +300,16 @@
|
|
|
264
300
|
$tableManualPagination = { ...pagination };
|
|
265
301
|
}
|
|
266
302
|
});
|
|
303
|
+
|
|
304
|
+
$effect(() => {
|
|
305
|
+
if (!enableChecked) return;
|
|
306
|
+
onselectionchange?.(selectedRows.map((row) => row.original));
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
$effect(() => {
|
|
310
|
+
if (!enableChecked) return;
|
|
311
|
+
onclearselection?.(clearSelection);
|
|
312
|
+
});
|
|
267
313
|
</script>
|
|
268
314
|
|
|
269
315
|
<section class="table-container">
|
|
@@ -334,7 +380,7 @@
|
|
|
334
380
|
<table class="table-main">
|
|
335
381
|
<Header headerGroups={table.getHeaderGroups()} {enableColumnSearch} />
|
|
336
382
|
{#if hasData}
|
|
337
|
-
<Body bodyRows={table.getRowModel().rows} {enableChecked} />
|
|
383
|
+
<Body bodyRows={table.getRowModel().rows} {enableChecked} {disabledRows} />
|
|
338
384
|
{/if}
|
|
339
385
|
</table>
|
|
340
386
|
</article>
|
|
@@ -2,31 +2,46 @@ import { type Snippet } from 'svelte';
|
|
|
2
2
|
import { type ColumnDef } from './adapter/index.js';
|
|
3
3
|
import type { ExcelSetting } from './excel-setting.js';
|
|
4
4
|
import { type Pagination } from './types.js';
|
|
5
|
+
interface BaseProps<T> {
|
|
6
|
+
columns: ColumnDef<T, any>[];
|
|
7
|
+
isLoading?: boolean;
|
|
8
|
+
data?: T[];
|
|
9
|
+
minPageSize?: boolean;
|
|
10
|
+
keepVisibleBulkActions?: boolean;
|
|
11
|
+
enableExportExcel?: boolean;
|
|
12
|
+
enableGlobalSearch?: boolean;
|
|
13
|
+
enableColumnSearch?: boolean;
|
|
14
|
+
enableColumnVisibility?: boolean;
|
|
15
|
+
enableAdvancedFilter?: boolean;
|
|
16
|
+
serverSide?: boolean;
|
|
17
|
+
pagination?: Pagination;
|
|
18
|
+
initialPage?: number;
|
|
19
|
+
initialPageSize?: number;
|
|
20
|
+
excelSetting?: ExcelSetting;
|
|
21
|
+
header?: Snippet;
|
|
22
|
+
bulkActions?: Snippet<[selectedRows: T[], clearSelection: VoidFunction]>;
|
|
23
|
+
onpagechange?: (pageSize: number, pageNumber: number) => void;
|
|
24
|
+
onpagesizechange?: (pageSize: number) => void;
|
|
25
|
+
onnextpage?: (pageSize: number, pageNumber: number) => void;
|
|
26
|
+
onprevpage?: (pageSize: number, pageNumber: number) => void;
|
|
27
|
+
}
|
|
28
|
+
interface TableWithCheckbox<T> extends BaseProps<T> {
|
|
29
|
+
enableChecked: true;
|
|
30
|
+
preselectedRows?: T[];
|
|
31
|
+
disabledRows?: T[];
|
|
32
|
+
onselectionchange?: (selectedRows: T[]) => void;
|
|
33
|
+
onclearselection?: (clearSelection: VoidFunction) => void;
|
|
34
|
+
}
|
|
35
|
+
interface TableWithoutCheckbox<T> extends BaseProps<T> {
|
|
36
|
+
enableChecked?: false;
|
|
37
|
+
preselectedRows?: never;
|
|
38
|
+
disabledRows?: never;
|
|
39
|
+
onselectionchange?: never;
|
|
40
|
+
onclearselection?: never;
|
|
41
|
+
}
|
|
42
|
+
type Props<T> = TableWithCheckbox<T> | TableWithoutCheckbox<T>;
|
|
5
43
|
declare function $$render<T extends object>(): {
|
|
6
|
-
props:
|
|
7
|
-
columns: ColumnDef<T, any>[];
|
|
8
|
-
isLoading?: boolean;
|
|
9
|
-
data?: T[];
|
|
10
|
-
minPageSize?: boolean;
|
|
11
|
-
enableChecked?: boolean;
|
|
12
|
-
keepVisibleBulkActions?: boolean;
|
|
13
|
-
enableExportExcel?: boolean;
|
|
14
|
-
enableGlobalSearch?: boolean;
|
|
15
|
-
enableColumnSearch?: boolean;
|
|
16
|
-
enableColumnVisibility?: boolean;
|
|
17
|
-
enableAdvancedFilter?: boolean;
|
|
18
|
-
serverSide?: boolean;
|
|
19
|
-
pagination?: Pagination;
|
|
20
|
-
initialPage?: number;
|
|
21
|
-
initialPageSize?: number;
|
|
22
|
-
excelSetting?: ExcelSetting;
|
|
23
|
-
header?: Snippet;
|
|
24
|
-
bulkActions?: Snippet<[selectedRows: T[], clearSelection: VoidFunction]>;
|
|
25
|
-
onpagechange?: (pageSize: number, pageNumber: number) => void;
|
|
26
|
-
onpagesizechange?: (pageSize: number) => void;
|
|
27
|
-
onnextpage?: (pageSize: number, pageNumber: number) => void;
|
|
28
|
-
onprevpage?: (pageSize: number, pageNumber: number) => void;
|
|
29
|
-
};
|
|
44
|
+
props: Props<T>;
|
|
30
45
|
exports: {};
|
|
31
46
|
bindings: "";
|
|
32
47
|
slots: {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type ColumnDef, type Row } from './adapter/index.js';
|
|
2
2
|
import type { Action, CursorPagination, Filter, PagePagination, Pagination } from './types.js';
|
|
3
|
-
export declare const createCheckedColumn: <T>() => import("./adapter/index.js").DisplayColumnDef<T, unknown>;
|
|
3
|
+
export declare const createCheckedColumn: <T>(disabledRows: T[]) => import("./adapter/index.js").DisplayColumnDef<T, unknown>;
|
|
4
4
|
export declare const createActionsColumn: <T>(getActions: (row: Row<T>) => Action[]) => import("./adapter/index.js").DisplayColumnDef<T, unknown>;
|
|
5
5
|
export declare const createStaticTable: <TData>(columns: ColumnDef<TData, any>[], data: TData[]) => import("./adapter/index.js").Table<TData>;
|
|
6
6
|
export declare const isValidPage: (value: number | undefined) => value is number;
|
|
@@ -2,7 +2,7 @@ import ActionsColumn from './ActionsColumn.svelte';
|
|
|
2
2
|
import RowCheckBox from './RowCheckBox.svelte';
|
|
3
3
|
import { createColumnHelper, createTable, getCoreRowModel, renderComponent } from './adapter/index.js';
|
|
4
4
|
import { DEFAULT_ITEMS_PER_PAGE_OPTIONS, DEFAULT_PAGE, DEFAULT_PAGE_LIMIT, Operation, Operator } from './consts.js';
|
|
5
|
-
export const createCheckedColumn = () => {
|
|
5
|
+
export const createCheckedColumn = (disabledRows) => {
|
|
6
6
|
const columnHelper = createColumnHelper();
|
|
7
7
|
return columnHelper.display({
|
|
8
8
|
id: 'checked',
|
|
@@ -12,12 +12,13 @@ export const createCheckedColumn = () => {
|
|
|
12
12
|
enableHiding: false,
|
|
13
13
|
header: ({ table }) => renderComponent(RowCheckBox, {
|
|
14
14
|
checked: table.getIsAllRowsSelected(),
|
|
15
|
+
disabled: disabledRows.length > 0,
|
|
15
16
|
indeterminate: table.getIsSomeRowsSelected(),
|
|
16
17
|
onchange: table.getToggleAllRowsSelectedHandler()
|
|
17
18
|
}),
|
|
18
19
|
cell: ({ row }) => renderComponent(RowCheckBox, {
|
|
19
20
|
checked: row.getIsSelected(),
|
|
20
|
-
disabled:
|
|
21
|
+
disabled: disabledRows.includes(row.original),
|
|
21
22
|
indeterminate: row.getIsSomeSelected(),
|
|
22
23
|
onchange: row.getToggleSelectedHandler()
|
|
23
24
|
}),
|
package/dist/utils/url.js
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import { base } from '$app/paths';
|
|
2
2
|
import { page } from '$app/state';
|
|
3
|
+
const normalizePathname = (path) => path.replace(/^\/v\d+\//, '/');
|
|
3
4
|
export const getNormalizedPathname = () => {
|
|
4
5
|
const pathname = page.url.pathname;
|
|
5
6
|
const withoutBase = base && pathname.startsWith(base) ? pathname.slice(base.length) : pathname;
|
|
6
|
-
return withoutBase
|
|
7
|
+
return normalizePathname(withoutBase);
|
|
7
8
|
};
|
|
8
9
|
export const getFirstPathSegment = (pathname) => {
|
|
9
10
|
const matchedPath = /^\/[^/]+/.exec(pathname);
|
|
10
11
|
return matchedPath?.[0] ?? '/';
|
|
11
12
|
};
|
|
12
13
|
export const existRoute = (url, pathname) => {
|
|
13
|
-
const
|
|
14
|
-
|
|
14
|
+
const normalizedPathname = normalizePathname(pathname);
|
|
15
|
+
const regex = new RegExp(`^${url}(?![\\w-])`);
|
|
16
|
+
return regex.test(normalizedPathname);
|
|
15
17
|
};
|