sveltacular 1.0.5 → 1.0.7
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/README.md +232 -28
- package/dist/forms/bool-box/bool-box.svelte +21 -2
- package/dist/forms/bool-box/bool-box.svelte.d.ts +5 -0
- package/dist/forms/check-box/check-box-group.svelte +1 -0
- package/dist/forms/check-box/check-box.svelte +73 -31
- package/dist/forms/check-box/check-box.svelte.d.ts +7 -0
- package/dist/forms/date-box/date-box.svelte +7 -3
- package/dist/forms/date-box/date-box.svelte.d.ts +3 -0
- package/dist/forms/file-box/file-box.svelte +33 -7
- package/dist/forms/form-field/form-field.svelte +128 -33
- package/dist/forms/form-field/form-field.svelte.d.ts +9 -3
- package/dist/forms/form-label/form-label.svelte +4 -2
- package/dist/forms/form-label/form-label.svelte.d.ts +2 -2
- package/dist/forms/index.d.ts +6 -2
- package/dist/forms/index.js +6 -3
- package/dist/forms/info-box/info-box.svelte +9 -7
- package/dist/forms/list-box/list-box.svelte +270 -89
- package/dist/forms/list-box/list-box.svelte.d.ts +3 -0
- package/dist/forms/money-box/money-box.svelte +20 -16
- package/dist/forms/number-box/number-box.svelte +16 -3
- package/dist/forms/number-box/number-box.svelte.d.ts +6 -0
- package/dist/forms/number-range-box/number-range-box.svelte +218 -0
- package/dist/forms/number-range-box/number-range-box.svelte.d.ts +21 -0
- package/dist/forms/phone-box/phone-box.svelte +17 -3
- package/dist/forms/phone-box/phone-box.svelte.d.ts +5 -0
- package/dist/forms/radio-group/radio-box.svelte +11 -2
- package/dist/forms/radio-group/radio-box.svelte.d.ts +1 -0
- package/dist/forms/radio-group/radio-group.svelte +10 -4
- package/dist/forms/radio-group/radio-group.svelte.d.ts +4 -0
- package/dist/forms/switch-box/switch-box.svelte +33 -13
- package/dist/forms/switch-box/switch-box.svelte.d.ts +6 -0
- package/dist/forms/tag-input-box/tag-input-box.svelte +204 -0
- package/dist/forms/tag-input-box/tag-input-box.svelte.d.ts +18 -0
- package/dist/forms/text-area/text-area.svelte +19 -3
- package/dist/forms/text-area/text-area.svelte.d.ts +7 -0
- package/dist/forms/text-box/text-box.svelte +18 -15
- package/dist/forms/text-box/text-box.svelte.d.ts +2 -2
- package/dist/forms/time-box/time-box.svelte +7 -3
- package/dist/forms/time-box/time-box.svelte.d.ts +3 -0
- package/dist/forms/url-box/url-box.svelte +31 -1
- package/dist/forms/url-box/url-box.svelte.d.ts +10 -0
- package/dist/generic/avatar/avatar.svelte +2 -0
- package/dist/generic/chip/chip.svelte +2 -0
- package/dist/generic/menu/menu.svelte +2 -3
- package/dist/navigation/context-menu/README.md +2 -0
- package/dist/navigation/context-menu/context-menu-divider.svelte +2 -0
- package/package.json +1 -1
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
</script>
|
|
33
33
|
|
|
34
34
|
<FormField {size} {label} {id} {required} {disabled}>
|
|
35
|
-
<div>
|
|
35
|
+
<div class="input">
|
|
36
36
|
<input
|
|
37
37
|
{id}
|
|
38
38
|
{placeholder}
|
|
@@ -48,21 +48,47 @@
|
|
|
48
48
|
</div>
|
|
49
49
|
</FormField>
|
|
50
50
|
|
|
51
|
-
<style
|
|
51
|
+
<style>.input {
|
|
52
|
+
display: flex;
|
|
53
|
+
align-items: center;
|
|
54
|
+
justify-content: flex-start;
|
|
55
|
+
position: relative;
|
|
52
56
|
width: 100%;
|
|
53
|
-
|
|
57
|
+
height: 100%;
|
|
58
|
+
box-sizing: border-box;
|
|
54
59
|
border-radius: var(--radius-md);
|
|
55
60
|
border: var(--border-thin) solid var(--form-input-border);
|
|
56
61
|
background-color: var(--form-input-bg);
|
|
57
62
|
color: var(--form-input-fg);
|
|
58
|
-
font-size: var(--font-
|
|
63
|
+
font-size: var(--font-md);
|
|
59
64
|
font-weight: 500;
|
|
60
|
-
line-height:
|
|
61
|
-
transition: background-color
|
|
65
|
+
line-height: 2rem;
|
|
66
|
+
transition: background-color var(--transition-base) var(--ease-in-out), border-color var(--transition-base) var(--ease-in-out), color var(--transition-base) var(--ease-in-out), fill var(--transition-base) var(--ease-in-out), stroke var(--transition-base) var(--ease-in-out);
|
|
62
67
|
user-select: none;
|
|
63
68
|
white-space: nowrap;
|
|
64
69
|
}
|
|
65
|
-
input
|
|
70
|
+
.input input {
|
|
71
|
+
width: 100%;
|
|
72
|
+
height: 100%;
|
|
73
|
+
box-sizing: border-box;
|
|
74
|
+
padding: 0;
|
|
75
|
+
padding-left: var(--spacing-base);
|
|
76
|
+
padding-right: var(--spacing-base);
|
|
77
|
+
margin: 0;
|
|
78
|
+
background-color: transparent;
|
|
79
|
+
border: none;
|
|
80
|
+
line-height: 2rem;
|
|
81
|
+
font-size: var(--font-md);
|
|
82
|
+
color: inherit;
|
|
83
|
+
}
|
|
84
|
+
.input input:focus {
|
|
85
|
+
outline: none;
|
|
86
|
+
}
|
|
87
|
+
.input input:focus-visible {
|
|
88
|
+
outline: 2px solid var(--focus-ring, #007bff);
|
|
89
|
+
outline-offset: 2px;
|
|
90
|
+
}
|
|
91
|
+
.input input::placeholder {
|
|
66
92
|
color: var(--form-input-placeholder, #888);
|
|
67
93
|
font-style: italic;
|
|
68
94
|
}</style>
|
|
@@ -1,18 +1,41 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
3
|
import type { ComponentSize } from '../../types/size.js';
|
|
4
|
-
import { getMaxWidth, getDisplayType } from '../../types/size.js';
|
|
5
4
|
import FormLabel from '../form-label/form-label.svelte';
|
|
5
|
+
import type { AriaRole } from 'svelte/elements';
|
|
6
|
+
|
|
7
|
+
export type FormFieldMessage = {
|
|
8
|
+
text: string;
|
|
9
|
+
isError?: boolean;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export type FormFieldFeedback = FormFieldMessage & {
|
|
13
|
+
details?: FormFieldMessage[];
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Maps size to flex-grow value for relative sizing in flexbox containers (FormRow).
|
|
18
|
+
* The size prop controls how much space the field takes relative to its siblings.
|
|
19
|
+
*/
|
|
20
|
+
const getFlexGrow = (size: ComponentSize): number => {
|
|
21
|
+
const flexMap: Record<ComponentSize, number> = {
|
|
22
|
+
sm: 1,
|
|
23
|
+
md: 2,
|
|
24
|
+
lg: 3,
|
|
25
|
+
xl: 4,
|
|
26
|
+
full: 4 // Map full to same as xl for backwards compatibility
|
|
27
|
+
};
|
|
28
|
+
return flexMap[size];
|
|
29
|
+
};
|
|
6
30
|
|
|
7
31
|
let {
|
|
8
|
-
size = '
|
|
32
|
+
size = 'md',
|
|
9
33
|
label = undefined,
|
|
10
34
|
id = undefined,
|
|
11
35
|
required = false,
|
|
12
36
|
disabled = false,
|
|
13
|
-
helperText
|
|
14
|
-
|
|
15
|
-
successText = undefined,
|
|
37
|
+
helperText,
|
|
38
|
+
feedback,
|
|
16
39
|
children
|
|
17
40
|
}: {
|
|
18
41
|
size?: ComponentSize;
|
|
@@ -20,36 +43,70 @@
|
|
|
20
43
|
id?: string | undefined;
|
|
21
44
|
required?: boolean;
|
|
22
45
|
disabled?: boolean;
|
|
23
|
-
helperText?: string
|
|
24
|
-
|
|
25
|
-
successText?: string | undefined;
|
|
46
|
+
helperText?: string;
|
|
47
|
+
feedback?: FormFieldFeedback;
|
|
26
48
|
children: Snippet;
|
|
27
49
|
} = $props();
|
|
28
50
|
|
|
29
|
-
let
|
|
30
|
-
|
|
51
|
+
let flexGrow = $derived(getFlexGrow(size));
|
|
52
|
+
|
|
53
|
+
// Determine which message to show: feedback takes precedence over helperText
|
|
54
|
+
let message = $derived.by<FormFieldFeedback | undefined>(() => {
|
|
55
|
+
if (feedback) return feedback;
|
|
56
|
+
if (helperText) {
|
|
57
|
+
return { text: helperText, isError: false };
|
|
58
|
+
}
|
|
59
|
+
return undefined;
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// Determine if we're showing helper text (no feedback) or actual feedback
|
|
63
|
+
let isHelperText = $derived(!feedback && !!helperText);
|
|
64
|
+
|
|
65
|
+
let ariaLive = $derived<'assertive' | 'polite' | undefined>(
|
|
66
|
+
message && !isHelperText ? (message.isError ? 'assertive' : 'polite') : undefined
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
let ariaRole = $derived<AriaRole | undefined>(
|
|
70
|
+
message && !isHelperText ? (message.isError ? 'alert' : 'status') : undefined
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
let messageClass = $derived(
|
|
74
|
+
message ? (isHelperText ? 'helper' : message.isError ? 'error' : 'success') : undefined
|
|
75
|
+
);
|
|
31
76
|
|
|
32
|
-
let
|
|
33
|
-
|
|
34
|
-
|
|
77
|
+
let messageId = $derived(
|
|
78
|
+
message && id
|
|
79
|
+
? isHelperText
|
|
80
|
+
? `${id}-helper`
|
|
81
|
+
: message.isError
|
|
82
|
+
? `${id}-error`
|
|
83
|
+
: `${id}-success`
|
|
84
|
+
: undefined
|
|
85
|
+
);
|
|
35
86
|
</script>
|
|
36
87
|
|
|
37
|
-
<div class="form-field {size}
|
|
88
|
+
<div class="form-field {size}" style="--flex-grow: {flexGrow};">
|
|
38
89
|
{#if label}
|
|
39
90
|
<FormLabel {id} {required} {disabled} {label} />
|
|
40
91
|
{/if}
|
|
41
92
|
{@render children?.()}
|
|
42
|
-
{#if
|
|
43
|
-
<div
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
{
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
93
|
+
{#if message}
|
|
94
|
+
<div
|
|
95
|
+
class="message-container {messageClass}"
|
|
96
|
+
role={ariaRole}
|
|
97
|
+
aria-live={ariaLive}
|
|
98
|
+
id={messageId}
|
|
99
|
+
>
|
|
100
|
+
<div class="message-text">{message.text}</div>
|
|
101
|
+
{#if message.details && message.details.length > 0}
|
|
102
|
+
<ul class="message-details">
|
|
103
|
+
{#each message.details as detail}
|
|
104
|
+
<li class="message-detail" class:error={detail.isError} class:success={!detail.isError}>
|
|
105
|
+
{detail.text}
|
|
106
|
+
</li>
|
|
107
|
+
{/each}
|
|
108
|
+
</ul>
|
|
109
|
+
{/if}
|
|
53
110
|
</div>
|
|
54
111
|
{/if}
|
|
55
112
|
</div>
|
|
@@ -61,7 +118,9 @@
|
|
|
61
118
|
display: flex;
|
|
62
119
|
flex-direction: column;
|
|
63
120
|
gap: 0.25rem;
|
|
64
|
-
flex: 1;
|
|
121
|
+
flex-grow: var(--flex-grow, 1);
|
|
122
|
+
flex-shrink: 1;
|
|
123
|
+
flex-basis: 0;
|
|
65
124
|
}
|
|
66
125
|
@media (max-width: 479.98px) {
|
|
67
126
|
.form-field {
|
|
@@ -69,18 +128,54 @@
|
|
|
69
128
|
}
|
|
70
129
|
}
|
|
71
130
|
|
|
72
|
-
.
|
|
131
|
+
.message-container {
|
|
132
|
+
display: flex;
|
|
133
|
+
flex-direction: column;
|
|
134
|
+
gap: 0.5rem;
|
|
73
135
|
font-size: var(--font-sm);
|
|
74
136
|
line-height: 1.25rem;
|
|
75
137
|
padding: var(--spacing-xs);
|
|
76
|
-
|
|
138
|
+
transition: color var(--transition-base) var(--ease-in-out), opacity var(--transition-base) var(--ease-in-out);
|
|
139
|
+
}
|
|
140
|
+
.message-container.helper {
|
|
141
|
+
color: var(--form-input-helper-text-fg, var(--body-fg-muted));
|
|
142
|
+
}
|
|
143
|
+
.message-container.success {
|
|
144
|
+
color: var(--color-success, #28a745);
|
|
145
|
+
font-weight: 500;
|
|
146
|
+
}
|
|
147
|
+
.message-container.error {
|
|
148
|
+
color: var(--color-error, #dc3545);
|
|
77
149
|
font-weight: 500;
|
|
78
150
|
}
|
|
79
151
|
|
|
80
|
-
.
|
|
81
|
-
font-size: var(--font-sm);
|
|
152
|
+
.message-text {
|
|
82
153
|
line-height: 1.25rem;
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.message-details {
|
|
157
|
+
list-style: none;
|
|
158
|
+
margin: 0;
|
|
159
|
+
padding: 0;
|
|
160
|
+
padding-left: var(--spacing-sm);
|
|
161
|
+
display: flex;
|
|
162
|
+
flex-direction: column;
|
|
163
|
+
gap: 0.1rem;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.message-detail {
|
|
167
|
+
font-size: var(--font-sm);
|
|
168
|
+
margin: 0;
|
|
169
|
+
padding: 0;
|
|
170
|
+
transition: color var(--transition-base) var(--ease-in-out), opacity var(--transition-base) var(--ease-in-out);
|
|
171
|
+
}
|
|
172
|
+
.message-detail::before {
|
|
173
|
+
content: "- ";
|
|
174
|
+
border-radius: 50%;
|
|
175
|
+
}
|
|
176
|
+
.message-detail.error {
|
|
177
|
+
color: var(--color-error, #dc3545);
|
|
178
|
+
}
|
|
179
|
+
.message-detail.success {
|
|
180
|
+
color: var(--color-success, #28a745);
|
|
86
181
|
}</style>
|
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
import type { Snippet } from 'svelte';
|
|
2
2
|
import type { ComponentSize } from '../../types/size.js';
|
|
3
|
+
export type FormFieldMessage = {
|
|
4
|
+
text: string;
|
|
5
|
+
isError?: boolean;
|
|
6
|
+
};
|
|
7
|
+
export type FormFieldFeedback = FormFieldMessage & {
|
|
8
|
+
details?: FormFieldMessage[];
|
|
9
|
+
};
|
|
3
10
|
type $$ComponentProps = {
|
|
4
11
|
size?: ComponentSize;
|
|
5
12
|
label?: string | undefined;
|
|
6
13
|
id?: string | undefined;
|
|
7
14
|
required?: boolean;
|
|
8
15
|
disabled?: boolean;
|
|
9
|
-
helperText?: string
|
|
10
|
-
|
|
11
|
-
successText?: string | undefined;
|
|
16
|
+
helperText?: string;
|
|
17
|
+
feedback?: FormFieldFeedback;
|
|
12
18
|
children: Snippet;
|
|
13
19
|
};
|
|
14
20
|
declare const FormField: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
disabled = false,
|
|
6
6
|
label = ''
|
|
7
7
|
}: {
|
|
8
|
-
id?: string
|
|
8
|
+
id?: string;
|
|
9
9
|
required?: boolean;
|
|
10
10
|
disabled?: boolean;
|
|
11
|
-
label
|
|
11
|
+
label: string;
|
|
12
12
|
} = $props();
|
|
13
13
|
</script>
|
|
14
14
|
|
|
@@ -19,10 +19,12 @@
|
|
|
19
19
|
margin-bottom: var(--spacing-sm);
|
|
20
20
|
font-weight: 500;
|
|
21
21
|
font-size: var(--font-base);
|
|
22
|
+
margin: 0;
|
|
22
23
|
}
|
|
23
24
|
label.required::after {
|
|
24
25
|
content: "*";
|
|
25
26
|
margin-left: var(--spacing-xs);
|
|
27
|
+
color: var(--color-danger);
|
|
26
28
|
}
|
|
27
29
|
label.disabled {
|
|
28
30
|
opacity: 0.5;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
type $$ComponentProps = {
|
|
2
|
-
id?: string
|
|
2
|
+
id?: string;
|
|
3
3
|
required?: boolean;
|
|
4
4
|
disabled?: boolean;
|
|
5
|
-
label
|
|
5
|
+
label: string;
|
|
6
6
|
};
|
|
7
7
|
declare const FormLabel: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
8
8
|
type FormLabel = ReturnType<typeof FormLabel>;
|
package/dist/forms/index.d.ts
CHANGED
|
@@ -7,8 +7,14 @@ export { default as InfoBox } from './info-box/info-box.svelte';
|
|
|
7
7
|
export { default as MoneyBox } from './money-box/money-box.svelte';
|
|
8
8
|
export { default as NewOrExistingCombo } from './combo/new-or-existing-combo.svelte';
|
|
9
9
|
export { default as NumberBox } from './number-box/number-box.svelte';
|
|
10
|
+
export { default as NumberRangeBox } from './number-range-box/number-range-box.svelte';
|
|
11
|
+
export { default as PhoneBox } from './phone-box/phone-box.svelte';
|
|
12
|
+
export { default as Slider } from './slider/slider.svelte';
|
|
13
|
+
export { default as SwitchBox } from './switch-box/switch-box.svelte';
|
|
14
|
+
export { default as TagInputBox } from './tag-input-box/tag-input-box.svelte';
|
|
10
15
|
export { default as TextArea } from './text-area/text-area.svelte';
|
|
11
16
|
export { default as TextBox } from './text-box/text-box.svelte';
|
|
17
|
+
export { default as TimeBox } from './time-box/time-box.svelte';
|
|
12
18
|
export { default as UrlBox } from './url-box/url-box.svelte';
|
|
13
19
|
export * from './check-box/index.js';
|
|
14
20
|
export * from './list-box/index.js';
|
|
@@ -21,6 +27,4 @@ export { default as FormHeader } from './form-header.svelte';
|
|
|
21
27
|
export { default as FormLabel } from './form-label/form-label.svelte';
|
|
22
28
|
export { default as FormSection } from './form-section/form-section.svelte';
|
|
23
29
|
export { default as FormRow } from './form-row/form-row.svelte';
|
|
24
|
-
export { default as Slider } from './slider/slider.svelte';
|
|
25
|
-
export { default as TimeBox } from './time-box/time-box.svelte';
|
|
26
30
|
export * from './validation.js';
|
package/dist/forms/index.js
CHANGED
|
@@ -8,8 +8,14 @@ export { default as InfoBox } from './info-box/info-box.svelte';
|
|
|
8
8
|
export { default as MoneyBox } from './money-box/money-box.svelte';
|
|
9
9
|
export { default as NewOrExistingCombo } from './combo/new-or-existing-combo.svelte';
|
|
10
10
|
export { default as NumberBox } from './number-box/number-box.svelte';
|
|
11
|
+
export { default as NumberRangeBox } from './number-range-box/number-range-box.svelte';
|
|
12
|
+
export { default as PhoneBox } from './phone-box/phone-box.svelte';
|
|
13
|
+
export { default as Slider } from './slider/slider.svelte';
|
|
14
|
+
export { default as SwitchBox } from './switch-box/switch-box.svelte';
|
|
15
|
+
export { default as TagInputBox } from './tag-input-box/tag-input-box.svelte';
|
|
11
16
|
export { default as TextArea } from './text-area/text-area.svelte';
|
|
12
17
|
export { default as TextBox } from './text-box/text-box.svelte';
|
|
18
|
+
export { default as TimeBox } from './time-box/time-box.svelte';
|
|
13
19
|
export { default as UrlBox } from './url-box/url-box.svelte';
|
|
14
20
|
// Form components with barrel files
|
|
15
21
|
export * from './check-box/index.js';
|
|
@@ -24,8 +30,5 @@ export { default as FormHeader } from './form-header.svelte';
|
|
|
24
30
|
export { default as FormLabel } from './form-label/form-label.svelte';
|
|
25
31
|
export { default as FormSection } from './form-section/form-section.svelte';
|
|
26
32
|
export { default as FormRow } from './form-row/form-row.svelte';
|
|
27
|
-
// New form components
|
|
28
|
-
export { default as Slider } from './slider/slider.svelte';
|
|
29
|
-
export { default as TimeBox } from './time-box/time-box.svelte';
|
|
30
33
|
// Validation utilities
|
|
31
34
|
export * from './validation.js';
|
|
@@ -30,16 +30,18 @@
|
|
|
30
30
|
</FormField>
|
|
31
31
|
|
|
32
32
|
<style>.input {
|
|
33
|
-
background-color: var(--form-input-disabled-bg
|
|
34
|
-
color: var(--form-input-fg
|
|
35
|
-
font-size:
|
|
33
|
+
background-color: var(--form-input-disabled-bg);
|
|
34
|
+
color: var(--form-input-fg);
|
|
35
|
+
font-size: var(--font-md);
|
|
36
36
|
width: 100%;
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
height: 100%;
|
|
38
|
+
padding-left: var(--spacing-base);
|
|
39
|
+
border-radius: var(--radius-md);
|
|
40
|
+
border: var(--border-thin) solid var(--form-input-border);
|
|
39
41
|
display: flex;
|
|
40
42
|
align-items: center;
|
|
41
43
|
justify-content: flex-start;
|
|
42
|
-
gap:
|
|
44
|
+
gap: var(--spacing-sm);
|
|
43
45
|
}
|
|
44
46
|
.input .icon {
|
|
45
47
|
display: block;
|
|
@@ -50,7 +52,7 @@
|
|
|
50
52
|
.input .text {
|
|
51
53
|
line-height: 2rem;
|
|
52
54
|
flex-grow: 1;
|
|
53
|
-
font-size:
|
|
55
|
+
font-size: var(--font-md);
|
|
54
56
|
}
|
|
55
57
|
.input a {
|
|
56
58
|
color: var(--form-input-fg, #000);
|