grav-svelte 0.0.98 → 0.0.99
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/Inputs/InputFormMail.svelte +171 -0
- package/dist/Inputs/InputFormMail.svelte.d.ts +22 -0
- package/dist/Inputs/InputFormPhone.svelte +229 -0
- package/dist/Inputs/InputFormPhone.svelte.d.ts +22 -0
- package/dist/Inputs/index.d.ts +2 -0
- package/dist/Inputs/index.js +2 -0
- package/package.json +1 -1
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import "../typography.css";
|
|
3
|
+
|
|
4
|
+
export let valueVar: string = "";
|
|
5
|
+
export let label: string;
|
|
6
|
+
export let disabled = false;
|
|
7
|
+
export let obligatory = false;
|
|
8
|
+
export let icon: string | null = null;
|
|
9
|
+
export let validation: boolean = false;
|
|
10
|
+
|
|
11
|
+
let validationMessage = "";
|
|
12
|
+
let isValid = true;
|
|
13
|
+
|
|
14
|
+
$: {
|
|
15
|
+
if (valueVar) {
|
|
16
|
+
// Email validation using standard regex
|
|
17
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
18
|
+
|
|
19
|
+
if (!emailRegex.test(valueVar)) {
|
|
20
|
+
validationMessage = "Invalid email format";
|
|
21
|
+
isValid = false;
|
|
22
|
+
} else {
|
|
23
|
+
validationMessage = "Email is valid";
|
|
24
|
+
isValid = true;
|
|
25
|
+
}
|
|
26
|
+
} else {
|
|
27
|
+
if (obligatory) {
|
|
28
|
+
validationMessage = "Email is required";
|
|
29
|
+
isValid = false;
|
|
30
|
+
} else {
|
|
31
|
+
validationMessage = "";
|
|
32
|
+
isValid = true;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
</script>
|
|
37
|
+
|
|
38
|
+
<div class="input-container">
|
|
39
|
+
{#if icon}
|
|
40
|
+
<div class="icon-wrapper">
|
|
41
|
+
<i class="{icon} icon"></i>
|
|
42
|
+
</div>
|
|
43
|
+
{/if}
|
|
44
|
+
<div class="input-wrapper">
|
|
45
|
+
<input
|
|
46
|
+
{disabled}
|
|
47
|
+
type="email"
|
|
48
|
+
bind:value={valueVar}
|
|
49
|
+
placeholder=" "
|
|
50
|
+
class="input-field"
|
|
51
|
+
/>
|
|
52
|
+
|
|
53
|
+
<label for={valueVar} class="input-label"
|
|
54
|
+
>{label}
|
|
55
|
+
{#if obligatory}
|
|
56
|
+
<span class="required-mark"> *</span>
|
|
57
|
+
{/if}</label
|
|
58
|
+
>
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
{#if validation && validationMessage}
|
|
62
|
+
<div
|
|
63
|
+
class="validation-message"
|
|
64
|
+
class:valid={isValid}
|
|
65
|
+
class:invalid={!isValid}
|
|
66
|
+
>
|
|
67
|
+
{validationMessage}
|
|
68
|
+
</div>
|
|
69
|
+
{/if}
|
|
70
|
+
|
|
71
|
+
<style>
|
|
72
|
+
.input-container {
|
|
73
|
+
display: flex;
|
|
74
|
+
align-items: center;
|
|
75
|
+
border: var(--grav-crud-input-border-width) solid
|
|
76
|
+
var(--grav-crud-color-neutral);
|
|
77
|
+
border-radius: 0.5rem;
|
|
78
|
+
padding-left: 0.5rem;
|
|
79
|
+
padding-right: 0.5rem;
|
|
80
|
+
padding-top: 0.2rem;
|
|
81
|
+
padding-bottom: 0.2rem;
|
|
82
|
+
margin-top: 1.95rem;
|
|
83
|
+
height: fit-content;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.icon-wrapper {
|
|
87
|
+
width: 1rem;
|
|
88
|
+
position: relative;
|
|
89
|
+
margin-right: 0.5rem;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.icon {
|
|
93
|
+
position: absolute;
|
|
94
|
+
top: -0.4rem;
|
|
95
|
+
left: 0.25rem;
|
|
96
|
+
color: var(--grav-crud-color-neutral);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.input-wrapper {
|
|
100
|
+
position: relative;
|
|
101
|
+
z-index: 0;
|
|
102
|
+
width: 100%;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.input-field {
|
|
106
|
+
display: block;
|
|
107
|
+
padding: 0.3rem;
|
|
108
|
+
width: 100%;
|
|
109
|
+
font-size: 1rem;
|
|
110
|
+
color: var(--grav-crud-color-neutral);
|
|
111
|
+
background: transparent;
|
|
112
|
+
appearance: none;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.input-field:focus {
|
|
116
|
+
outline: none;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.input-label {
|
|
120
|
+
position: absolute;
|
|
121
|
+
font-size: 1rem;
|
|
122
|
+
text-align: left;
|
|
123
|
+
color: var(--grav-crud-color-neutral);
|
|
124
|
+
transition: all 0.3s;
|
|
125
|
+
top: 0.25rem;
|
|
126
|
+
left: 0.25rem;
|
|
127
|
+
z-index: -10;
|
|
128
|
+
transform-origin: left;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.input-field:focus + .input-label,
|
|
132
|
+
.input-field:not(:placeholder-shown) + .input-label {
|
|
133
|
+
left: 0;
|
|
134
|
+
top: 0;
|
|
135
|
+
color: var(--grav-crud-color-neutral);
|
|
136
|
+
translate: -0.6rem -2.05rem;
|
|
137
|
+
scale: 1;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.input-field:placeholder-shown + .input-label {
|
|
141
|
+
transform: translateY(0) scale(1);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.required-mark {
|
|
145
|
+
color: #dc2626;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.no-margin {
|
|
149
|
+
margin-top: 0;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.no-margin .input-field:focus + .input-label,
|
|
153
|
+
.no-margin .input-field:not(:placeholder-shown) + .input-label {
|
|
154
|
+
translate: -0.6rem -1.4rem;
|
|
155
|
+
font-size: 0.7rem;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.validation-message {
|
|
159
|
+
font-size: 0.875rem;
|
|
160
|
+
margin-top: 0.25rem;
|
|
161
|
+
color: var(--grav-crud-color-neutral);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.validation-message.valid {
|
|
165
|
+
color: #10b981;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.validation-message.invalid {
|
|
169
|
+
color: #dc2626;
|
|
170
|
+
}
|
|
171
|
+
</style>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { SvelteComponentTyped } from "svelte";
|
|
2
|
+
import "../typography.css";
|
|
3
|
+
declare const __propDef: {
|
|
4
|
+
props: {
|
|
5
|
+
valueVar?: string;
|
|
6
|
+
label: string;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
obligatory?: boolean;
|
|
9
|
+
icon?: string | null;
|
|
10
|
+
validation?: boolean;
|
|
11
|
+
};
|
|
12
|
+
events: {
|
|
13
|
+
[evt: string]: CustomEvent<any>;
|
|
14
|
+
};
|
|
15
|
+
slots: {};
|
|
16
|
+
};
|
|
17
|
+
export type InputFormMailProps = typeof __propDef.props;
|
|
18
|
+
export type InputFormMailEvents = typeof __propDef.events;
|
|
19
|
+
export type InputFormMailSlots = typeof __propDef.slots;
|
|
20
|
+
export default class InputFormMail extends SvelteComponentTyped<InputFormMailProps, InputFormMailEvents, InputFormMailSlots> {
|
|
21
|
+
}
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import "../typography.css";
|
|
3
|
+
|
|
4
|
+
interface CountryOption {
|
|
5
|
+
value: string;
|
|
6
|
+
label: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export let valueVar: string = "";
|
|
10
|
+
export let label: string;
|
|
11
|
+
export let disabled = false;
|
|
12
|
+
export let obligatory = false;
|
|
13
|
+
export let defaultDialCode: string = "+52";
|
|
14
|
+
export let validation: boolean = false;
|
|
15
|
+
|
|
16
|
+
// Internal state
|
|
17
|
+
let selectedDialCode: string = defaultDialCode;
|
|
18
|
+
let phoneNumber: string = "";
|
|
19
|
+
let validationMessage = "";
|
|
20
|
+
let isValid = true;
|
|
21
|
+
|
|
22
|
+
// Country list with flag emojis (only flag + dial code)
|
|
23
|
+
const countries: CountryOption[] = [
|
|
24
|
+
{ value: "+1", label: "🇺🇸 +1" },
|
|
25
|
+
{ value: "+1", label: "🇨🇦 +1" },
|
|
26
|
+
{ value: "+52", label: "🇲🇽 +52" },
|
|
27
|
+
{ value: "+34", label: "🇪🇸 +34" },
|
|
28
|
+
{ value: "+54", label: "🇦🇷 +54" },
|
|
29
|
+
{ value: "+56", label: "🇨🇱 +56" },
|
|
30
|
+
{ value: "+57", label: "🇨🇴 +57" },
|
|
31
|
+
{ value: "+51", label: "🇵🇪 +51" },
|
|
32
|
+
{ value: "+58", label: "🇻🇪 +58" },
|
|
33
|
+
{ value: "+593", label: "🇪🇨 +593" },
|
|
34
|
+
{ value: "+55", label: "🇧🇷 +55" },
|
|
35
|
+
{ value: "+598", label: "🇺🇾 +598" },
|
|
36
|
+
{ value: "+595", label: "🇵🇾 +595" },
|
|
37
|
+
{ value: "+591", label: "🇧🇴 +591" },
|
|
38
|
+
{ value: "+506", label: "🇨🇷 +506" },
|
|
39
|
+
{ value: "+502", label: "🇬🇹 +502" },
|
|
40
|
+
{ value: "+504", label: "🇭🇳 +504" },
|
|
41
|
+
{ value: "+505", label: "🇳🇮 +505" },
|
|
42
|
+
{ value: "+507", label: "🇵🇦 +507" },
|
|
43
|
+
{ value: "+503", label: "🇸🇻 +503" },
|
|
44
|
+
{ value: "+1", label: "🇩🇴 +1" },
|
|
45
|
+
{ value: "+1", label: "🇵🇷 +1" },
|
|
46
|
+
{ value: "+53", label: "🇨🇺 +53" },
|
|
47
|
+
{ value: "+44", label: "🇬🇧 +44" },
|
|
48
|
+
{ value: "+33", label: "🇫🇷 +33" },
|
|
49
|
+
{ value: "+49", label: "🇩🇪 +49" },
|
|
50
|
+
{ value: "+39", label: "🇮🇹 +39" },
|
|
51
|
+
{ value: "+351", label: "🇵🇹 +351" },
|
|
52
|
+
{ value: "+31", label: "🇳🇱 +31" },
|
|
53
|
+
{ value: "+32", label: "🇧🇪 +32" },
|
|
54
|
+
];
|
|
55
|
+
|
|
56
|
+
// Concatenate dial code and phone number
|
|
57
|
+
$: {
|
|
58
|
+
if (selectedDialCode && phoneNumber) {
|
|
59
|
+
valueVar = selectedDialCode + phoneNumber.replace(/\D/g, "");
|
|
60
|
+
} else if (selectedDialCode) {
|
|
61
|
+
valueVar = selectedDialCode;
|
|
62
|
+
} else {
|
|
63
|
+
valueVar = "";
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Validation logic
|
|
67
|
+
if (validation) {
|
|
68
|
+
const cleanNumber = phoneNumber.replace(/\D/g, "");
|
|
69
|
+
|
|
70
|
+
if (phoneNumber && !/^\d+$/.test(cleanNumber)) {
|
|
71
|
+
validationMessage = "Phone number must contain only digits";
|
|
72
|
+
isValid = false;
|
|
73
|
+
} else if (cleanNumber && cleanNumber.length < 7) {
|
|
74
|
+
validationMessage = "Phone number must be at least 7 digits";
|
|
75
|
+
isValid = false;
|
|
76
|
+
} else if (cleanNumber && cleanNumber.length > 15) {
|
|
77
|
+
validationMessage = "Phone number must not exceed 15 digits";
|
|
78
|
+
isValid = false;
|
|
79
|
+
} else if (cleanNumber) {
|
|
80
|
+
validationMessage = "Phone number is valid";
|
|
81
|
+
isValid = true;
|
|
82
|
+
} else {
|
|
83
|
+
validationMessage = "";
|
|
84
|
+
isValid = true;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Clean phone number input (only allow digits)
|
|
90
|
+
function handlePhoneInput(event: Event) {
|
|
91
|
+
const input = event.target as HTMLInputElement;
|
|
92
|
+
const cleaned = input.value.replace(/\D/g, "");
|
|
93
|
+
phoneNumber = cleaned;
|
|
94
|
+
}
|
|
95
|
+
</script>
|
|
96
|
+
|
|
97
|
+
<div class="phone-container">
|
|
98
|
+
<label class="phone-label">
|
|
99
|
+
{label}
|
|
100
|
+
{#if obligatory}
|
|
101
|
+
<span class="required-mark"> *</span>
|
|
102
|
+
{/if}
|
|
103
|
+
</label>
|
|
104
|
+
|
|
105
|
+
<div class="phone-input-wrapper">
|
|
106
|
+
<div class="country-select-wrapper">
|
|
107
|
+
<select
|
|
108
|
+
bind:value={selectedDialCode}
|
|
109
|
+
{disabled}
|
|
110
|
+
class="country-select"
|
|
111
|
+
>
|
|
112
|
+
{#each countries as country}
|
|
113
|
+
<option value={country.value}>{country.label}</option>
|
|
114
|
+
{/each}
|
|
115
|
+
</select>
|
|
116
|
+
</div>
|
|
117
|
+
|
|
118
|
+
<div class="phone-number-wrapper">
|
|
119
|
+
<input
|
|
120
|
+
type="tel"
|
|
121
|
+
bind:value={phoneNumber}
|
|
122
|
+
on:input={handlePhoneInput}
|
|
123
|
+
{disabled}
|
|
124
|
+
placeholder="Phone number"
|
|
125
|
+
class="phone-input"
|
|
126
|
+
/>
|
|
127
|
+
</div>
|
|
128
|
+
</div>
|
|
129
|
+
|
|
130
|
+
{#if validation && validationMessage}
|
|
131
|
+
<div
|
|
132
|
+
class="validation-message"
|
|
133
|
+
class:valid={isValid}
|
|
134
|
+
class:invalid={!isValid}
|
|
135
|
+
>
|
|
136
|
+
{validationMessage}
|
|
137
|
+
</div>
|
|
138
|
+
{/if}
|
|
139
|
+
</div>
|
|
140
|
+
|
|
141
|
+
<style>
|
|
142
|
+
.phone-container {
|
|
143
|
+
display: flex;
|
|
144
|
+
flex-direction: column;
|
|
145
|
+
width: 100%;
|
|
146
|
+
margin-top: 1.95rem;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.phone-label {
|
|
150
|
+
font-size: 1rem;
|
|
151
|
+
color: var(--grav-crud-color-neutral);
|
|
152
|
+
margin-bottom: 0.25rem;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.required-mark {
|
|
156
|
+
color: #dc2626;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
.phone-input-wrapper {
|
|
160
|
+
display: grid;
|
|
161
|
+
grid-template-columns: 80px 1fr;
|
|
162
|
+
border: var(--grav-crud-input-border-width) solid
|
|
163
|
+
var(--grav-crud-color-neutral);
|
|
164
|
+
border-radius: 0.5rem;
|
|
165
|
+
overflow: hidden;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.country-select-wrapper {
|
|
169
|
+
border-right: var(--grav-crud-input-border-width) solid
|
|
170
|
+
var(--grav-crud-color-neutral);
|
|
171
|
+
background-color: transparent;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.country-select {
|
|
175
|
+
width: 100%;
|
|
176
|
+
height: 100%;
|
|
177
|
+
padding: 0.5rem;
|
|
178
|
+
padding-right: 0.25rem;
|
|
179
|
+
font-size: 1rem;
|
|
180
|
+
color: var(--grav-crud-color-neutral);
|
|
181
|
+
background-color: transparent;
|
|
182
|
+
border: none;
|
|
183
|
+
outline: none;
|
|
184
|
+
cursor: pointer;
|
|
185
|
+
appearance: none;
|
|
186
|
+
-webkit-appearance: none;
|
|
187
|
+
-moz-appearance: none;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.country-select:disabled {
|
|
191
|
+
cursor: not-allowed;
|
|
192
|
+
opacity: 0.6;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.phone-number-wrapper {
|
|
196
|
+
display: flex;
|
|
197
|
+
align-items: center;
|
|
198
|
+
padding: 0 0.5rem;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
.phone-input {
|
|
202
|
+
width: 100%;
|
|
203
|
+
padding: 0.5rem;
|
|
204
|
+
font-size: 1rem;
|
|
205
|
+
color: var(--grav-crud-color-neutral);
|
|
206
|
+
background: transparent;
|
|
207
|
+
border: none;
|
|
208
|
+
outline: none;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
.phone-input::placeholder {
|
|
212
|
+
color: var(--grav-crud-color-neutral);
|
|
213
|
+
opacity: 0.5;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
.validation-message {
|
|
217
|
+
font-size: 0.875rem;
|
|
218
|
+
margin-top: 0.25rem;
|
|
219
|
+
color: var(--grav-crud-color-neutral);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.validation-message.valid {
|
|
223
|
+
color: #10b981;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.validation-message.invalid {
|
|
227
|
+
color: #dc2626;
|
|
228
|
+
}
|
|
229
|
+
</style>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { SvelteComponentTyped } from "svelte";
|
|
2
|
+
import "../typography.css";
|
|
3
|
+
declare const __propDef: {
|
|
4
|
+
props: {
|
|
5
|
+
valueVar?: string;
|
|
6
|
+
label: string;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
obligatory?: boolean;
|
|
9
|
+
defaultDialCode?: string;
|
|
10
|
+
validation?: boolean;
|
|
11
|
+
};
|
|
12
|
+
events: {
|
|
13
|
+
[evt: string]: CustomEvent<any>;
|
|
14
|
+
};
|
|
15
|
+
slots: {};
|
|
16
|
+
};
|
|
17
|
+
export type InputFormPhoneProps = typeof __propDef.props;
|
|
18
|
+
export type InputFormPhoneEvents = typeof __propDef.events;
|
|
19
|
+
export type InputFormPhoneSlots = typeof __propDef.slots;
|
|
20
|
+
export default class InputFormPhone extends SvelteComponentTyped<InputFormPhoneProps, InputFormPhoneEvents, InputFormPhoneSlots> {
|
|
21
|
+
}
|
|
22
|
+
export {};
|
package/dist/Inputs/index.d.ts
CHANGED
|
@@ -9,4 +9,6 @@ export { default as InputFormNumber } from './InputFormNumber.svelte';
|
|
|
9
9
|
export { default as InputFormSelect } from './InputFormSelect.svelte';
|
|
10
10
|
export { default as InputFormText } from './InputFormText.svelte';
|
|
11
11
|
export { default as InputFormPassword } from './InputFormPassword.svelte';
|
|
12
|
+
export { default as InputFormMail } from './InputFormMail.svelte';
|
|
13
|
+
export { default as InputFormPhone } from './InputFormPhone.svelte';
|
|
12
14
|
export { default as InputFormTextArea } from './InputFormTextArea.svelte';
|
package/dist/Inputs/index.js
CHANGED
|
@@ -9,4 +9,6 @@ export { default as InputFormNumber } from './InputFormNumber.svelte';
|
|
|
9
9
|
export { default as InputFormSelect } from './InputFormSelect.svelte';
|
|
10
10
|
export { default as InputFormText } from './InputFormText.svelte';
|
|
11
11
|
export { default as InputFormPassword } from './InputFormPassword.svelte';
|
|
12
|
+
export { default as InputFormMail } from './InputFormMail.svelte';
|
|
13
|
+
export { default as InputFormPhone } from './InputFormPhone.svelte';
|
|
12
14
|
export { default as InputFormTextArea } from './InputFormTextArea.svelte';
|