|
2 | 2 | export let id: string = "input-" + Math.random().toString(36).substring(2, 8);
|
3 | 3 | export let label: string;
|
4 | 4 | export let placeholder: string;
|
5 |
| - export let type: "text" | "email" | "password" | "url" | "search" = "text"; |
| 5 | + export let type: "text" | "email" | "password" | "url" | "search" | "username" = "text"; |
6 | 6 | export let value: string = "";
|
7 | 7 | export let disabled: boolean = false;
|
8 | 8 | export let invalid: boolean = false;
|
9 | 9 | export let invalidMessage: string = "Invalid";
|
| 10 | + export let required: boolean = false; |
10 | 11 | export let onEnter: (event: KeyboardEvent) => void = () => {};
|
11 | 12 | </script>
|
12 | 13 |
|
13 | 14 | <div class="input-root">
|
14 |
| - <label for={id}>{label}</label> |
| 15 | + <label for={id}> |
| 16 | + {label} |
| 17 | + {#if required} |
| 18 | + <span aria-hidden="true" style="color: red;">*</span> |
| 19 | + {/if} |
| 20 | + </label> |
15 | 21 | <input
|
16 | 22 | {id}
|
17 | 23 | {type}
|
18 | 24 | {placeholder}
|
19 | 25 | {disabled}
|
20 |
| - bind:value |
| 26 | + {required} |
| 27 | + aria-required={required} |
21 | 28 | aria-invalid={invalid}
|
22 | 29 | aria-describedby={invalid ? id + "-error" : undefined}
|
23 |
| - on:keypress={(event) => { |
| 30 | + bind:value |
| 31 | + on:keydown={(event) => { |
24 | 32 | if (event.key === "Enter" && onEnter) {
|
25 | 33 | onEnter(event);
|
26 | 34 | }
|
27 | 35 | }}
|
28 | 36 | />
|
29 | 37 | {#if invalid}
|
30 | 38 | <div id={id + "-error"} class="error-message">
|
31 |
| - <p> |
32 |
| - <span class="material-symbols-outlined" aria-hidden="true">error</span> |
33 |
| - {invalidMessage} |
34 |
| - </p> |
| 39 | + <span class="material-symbols-outlined" aria-hidden="true">error</span> |
| 40 | + {invalidMessage} |
35 | 41 | </div>
|
36 | 42 | {/if}
|
37 | 43 | </div>
|
|
50 | 56 |
|
51 | 57 | input {
|
52 | 58 | all: unset;
|
| 59 | + border: 1px solid transparent; |
53 | 60 | border-radius: 8px;
|
54 | 61 | cursor: text;
|
55 | 62 | padding: 0.5rem;
|
56 | 63 | font-family: var(--token-font-main);
|
57 | 64 | background-color: var(--token-color-surface-raised-normal);
|
| 65 | + transition: border-color 0.2s; |
58 | 66 | }
|
59 | 67 |
|
60 |
| - .error-message { |
61 |
| - color: var(--token-color-text-danger); |
| 68 | + input:focus { |
| 69 | + border-color: var(--token-color-primary); |
| 70 | + outline: none; |
62 | 71 | }
|
63 | 72 |
|
64 |
| - p { |
65 |
| - font-size: 1rem; |
66 |
| - vertical-align: middle; |
| 73 | + input[aria-invalid="true"] { |
| 74 | + border-color: var(--token-color-text-danger); |
| 75 | + } |
| 76 | +
|
| 77 | + .error-message { |
67 | 78 | display: flex;
|
| 79 | + flex-direction: row; |
68 | 80 | align-items: center;
|
69 |
| - gap: 0.25rem; |
| 81 | + color: var(--token-color-text-danger); |
| 82 | + gap: var(--token-space-1); |
| 83 | + vertical-align: middle; |
70 | 84 | }
|
71 | 85 |
|
72 |
| - span { |
| 86 | + span.material-symbols-outlined { |
73 | 87 | font-size: 1.2rem;
|
74 | 88 | }
|
75 | 89 | </style>
|
0 commit comments