@iroco/ui 1.15.1 → 1.15.3

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.
@@ -134,7 +134,7 @@
134
134
  display: flex;
135
135
  flex-direction: column;
136
136
  }
137
- .iroco-ui-form .iroco-ui-input > input {
137
+ .iroco-ui-form .iroco-ui-input input {
138
138
  color: var(--color-text);
139
139
  background: var(--color-body);
140
140
  border: 1px solid var(--color-border);
@@ -144,19 +144,19 @@
144
144
  overflow: hidden;
145
145
  border-radius: 0.5em;
146
146
  }
147
- .iroco-ui-form .iroco-ui-input > input::placeholder {
147
+ .iroco-ui-form .iroco-ui-input input::placeholder {
148
148
  color: var(--form-text-placeholder);
149
149
  }
150
- .iroco-ui-form .iroco-ui-input > input.error {
150
+ .iroco-ui-form .iroco-ui-input input.error {
151
151
  border-color: var(--color-danger);
152
152
  }
153
- .iroco-ui-form .iroco-ui-input > input.error:focus {
153
+ .iroco-ui-form .iroco-ui-input input.error:focus {
154
154
  outline-color: var(--color-danger);
155
155
  }
156
- .iroco-ui-form .iroco-ui-input > input.readonlyInput {
156
+ .iroco-ui-form .iroco-ui-input input.readonlyInput {
157
157
  cursor: not-allowed;
158
158
  }
159
- .iroco-ui-form .iroco-ui-input > input.border {
159
+ .iroco-ui-form .iroco-ui-input input.border {
160
160
  border: 1px solid var(--form-element-border);
161
161
  }
162
162
  .iroco-ui-form .iroco-ui-label {
@@ -31,3 +31,4 @@
31
31
  {/snippet}
32
32
 
33
33
  <Story name="Default" />
34
+ <Story name="Label" args={{ label: 'Label' }} />
@@ -19,6 +19,9 @@
19
19
  readonly?: boolean;
20
20
  border?: boolean;
21
21
  oninput?: FormEventHandler<HTMLInputElement> | null | undefined;
22
+ showPasswordAriaLabel?: string | null;
23
+ passwordShownAriaLive?: string | null;
24
+ passwordHiddenAriaLive?: string | null;
22
25
  }
23
26
 
24
27
  let {
@@ -36,14 +39,24 @@
36
39
  border = false,
37
40
  autocomplete = 'on',
38
41
  oninput,
42
+ showPasswordAriaLabel = 'Show password',
43
+ passwordShownAriaLive = 'password visible',
44
+ passwordHiddenAriaLive = 'password hidden',
45
+
39
46
  ...rest
40
47
  }: Props = $props();
41
48
 
42
- let showPassword = $state(false);
43
- let fieldType: 'password' | 'text' = $derived(showPassword ? 'text' : 'password');
49
+ const HANDLED_KEYS = new Set(['Space', 'Enter']);
50
+
51
+ let passwordShown = $state(false);
52
+ let fieldType: 'password' | 'text' = $derived(passwordShown ? 'text' : 'password');
53
+
54
+ function showPassword() {
55
+ passwordShown = true;
56
+ }
44
57
 
45
- function toggleShowPassword() {
46
- showPassword = !showPassword;
58
+ function hidePassword() {
59
+ passwordShown = false;
47
60
  }
48
61
 
49
62
  function hasErrors() {
@@ -55,25 +68,41 @@
55
68
  {#if label}
56
69
  <label class="iroco-ui-label" for={id}>{label}</label>
57
70
  {/if}
58
- <input
59
- type={fieldType}
60
- {oninput}
61
- bind:value
62
- {onfocus}
63
- {onblur}
64
- {id}
65
- {name}
66
- {placeholder}
67
- {autocomplete}
68
- class:border
69
- class:error={hasErrors()}
70
- class:readonlyInput={readonly === true}
71
- {readonly}
72
- {...rest}
73
- />
74
- <button type="button" onclick={toggleShowPassword}>
75
- <Icon data={eye} />
76
- </button>
71
+ <div class="iroco-ui-input__field">
72
+ <input
73
+ type={fieldType}
74
+ {oninput}
75
+ bind:value
76
+ {onfocus}
77
+ {onblur}
78
+ {id}
79
+ {name}
80
+ {placeholder}
81
+ {autocomplete}
82
+ class:border
83
+ class:error={hasErrors()}
84
+ class:readonlyInput={readonly === true}
85
+ {readonly}
86
+ {...rest}
87
+ />
88
+ <button
89
+ type="button"
90
+ onpointerdown={showPassword}
91
+ onpointerup={hidePassword}
92
+ onpointerleave={hidePassword}
93
+ onpointercancel={hidePassword}
94
+ onkeydown={(e) => HANDLED_KEYS.has(e.code) && showPassword()}
95
+ onkeyup={(e) => HANDLED_KEYS.has(e.code) && hidePassword()}
96
+ onblur={hidePassword}
97
+ aria-label={showPasswordAriaLabel}
98
+ aria-pressed={passwordShown}
99
+ >
100
+ <Icon data={eye} />
101
+ </button>
102
+ <div class="password-aria-live" aria-live="assertive">
103
+ {passwordShown ? passwordShownAriaLive : passwordHiddenAriaLive}
104
+ </div>
105
+ </div>
77
106
  {#if error != null}
78
107
  <p data-testid="error" class="error">
79
108
  {#if htmlError}
@@ -200,7 +229,7 @@
200
229
  display: flex;
201
230
  flex-direction: column;
202
231
  }
203
- .iroco-ui-form .iroco-ui-input > input {
232
+ .iroco-ui-form .iroco-ui-input input {
204
233
  color: var(--color-text);
205
234
  background: var(--color-body);
206
235
  border: 1px solid var(--color-border);
@@ -210,19 +239,19 @@
210
239
  overflow: hidden;
211
240
  border-radius: 0.5em;
212
241
  }
213
- .iroco-ui-form .iroco-ui-input > input::placeholder {
242
+ .iroco-ui-form .iroco-ui-input input::placeholder {
214
243
  color: var(--form-text-placeholder);
215
244
  }
216
- .iroco-ui-form .iroco-ui-input > input.error {
245
+ .iroco-ui-form .iroco-ui-input input.error {
217
246
  border-color: var(--color-danger);
218
247
  }
219
- .iroco-ui-form .iroco-ui-input > input.error:focus {
248
+ .iroco-ui-form .iroco-ui-input input.error:focus {
220
249
  outline-color: var(--color-danger);
221
250
  }
222
- .iroco-ui-form .iroco-ui-input > input.readonlyInput {
251
+ .iroco-ui-form .iroco-ui-input input.readonlyInput {
223
252
  cursor: not-allowed;
224
253
  }
225
- .iroco-ui-form .iroco-ui-input > input.border {
254
+ .iroco-ui-form .iroco-ui-input input.border {
226
255
  border: 1px solid var(--form-element-border);
227
256
  }
228
257
  .iroco-ui-form .iroco-ui-label {
@@ -278,17 +307,28 @@
278
307
  position: relative;
279
308
  width: 100%;
280
309
  }
281
- .iroco-ui-input input {
310
+ .iroco-ui-input__field {
311
+ position: relative;
312
+ display: flex;
313
+ align-items: center;
314
+ }
315
+ .iroco-ui-input__field input {
282
316
  width: 100%;
283
- padding-right: 35px;
317
+ padding-right: 1em;
284
318
  }
285
- .iroco-ui-input button {
319
+ .iroco-ui-input__field button {
286
320
  position: absolute;
287
- right: 10px;
288
- top: 50%;
289
- transform: translateY(-50%);
321
+ right: 1rem;
322
+ background: none;
323
+ border: none;
290
324
  cursor: pointer;
325
+ padding: 0;
326
+ display: flex;
327
+ align-items: center;
291
328
  color: var(--color-foreground);
292
- background-color: transparent;
293
- border: none;
329
+ }
330
+
331
+ .password-aria-live {
332
+ width: 0;
333
+ overflow: hidden;
294
334
  }</style>
@@ -17,6 +17,9 @@ interface Props extends HTMLInputAttributes {
17
17
  readonly?: boolean;
18
18
  border?: boolean;
19
19
  oninput?: FormEventHandler<HTMLInputElement> | null | undefined;
20
+ showPasswordAriaLabel?: string | null;
21
+ passwordShownAriaLive?: string | null;
22
+ passwordHiddenAriaLive?: string | null;
20
23
  }
21
24
  declare const PasswordInput: import("svelte").Component<Props, {}, "value">;
22
25
  type PasswordInput = ReturnType<typeof PasswordInput>;
@@ -130,7 +130,7 @@
130
130
  display: flex;
131
131
  flex-direction: column;
132
132
  }
133
- .iroco-ui-form .iroco-ui-input > input {
133
+ .iroco-ui-form .iroco-ui-input input {
134
134
  color: var(--color-text);
135
135
  background: var(--color-body);
136
136
  border: 1px solid var(--color-border);
@@ -140,19 +140,19 @@
140
140
  overflow: hidden;
141
141
  border-radius: 0.5em;
142
142
  }
143
- .iroco-ui-form .iroco-ui-input > input::placeholder {
143
+ .iroco-ui-form .iroco-ui-input input::placeholder {
144
144
  color: var(--form-text-placeholder);
145
145
  }
146
- .iroco-ui-form .iroco-ui-input > input.error {
146
+ .iroco-ui-form .iroco-ui-input input.error {
147
147
  border-color: var(--color-danger);
148
148
  }
149
- .iroco-ui-form .iroco-ui-input > input.error:focus {
149
+ .iroco-ui-form .iroco-ui-input input.error:focus {
150
150
  outline-color: var(--color-danger);
151
151
  }
152
- .iroco-ui-form .iroco-ui-input > input.readonlyInput {
152
+ .iroco-ui-form .iroco-ui-input input.readonlyInput {
153
153
  cursor: not-allowed;
154
154
  }
155
- .iroco-ui-form .iroco-ui-input > input.border {
155
+ .iroco-ui-form .iroco-ui-input input.border {
156
156
  border: 1px solid var(--form-element-border);
157
157
  }
158
158
  .iroco-ui-form .iroco-ui-label {
@@ -192,7 +192,7 @@
192
192
  display: flex;
193
193
  flex-direction: column;
194
194
  }
195
- .iroco-ui-form .iroco-ui-input > input {
195
+ .iroco-ui-form .iroco-ui-input input {
196
196
  color: var(--color-text);
197
197
  background: var(--color-body);
198
198
  border: 1px solid var(--color-border);
@@ -202,19 +202,19 @@
202
202
  overflow: hidden;
203
203
  border-radius: 0.5em;
204
204
  }
205
- .iroco-ui-form .iroco-ui-input > input::placeholder {
205
+ .iroco-ui-form .iroco-ui-input input::placeholder {
206
206
  color: var(--form-text-placeholder);
207
207
  }
208
- .iroco-ui-form .iroco-ui-input > input.error {
208
+ .iroco-ui-form .iroco-ui-input input.error {
209
209
  border-color: var(--color-danger);
210
210
  }
211
- .iroco-ui-form .iroco-ui-input > input.error:focus {
211
+ .iroco-ui-form .iroco-ui-input input.error:focus {
212
212
  outline-color: var(--color-danger);
213
213
  }
214
- .iroco-ui-form .iroco-ui-input > input.readonlyInput {
214
+ .iroco-ui-form .iroco-ui-input input.readonlyInput {
215
215
  cursor: not-allowed;
216
216
  }
217
- .iroco-ui-form .iroco-ui-input > input.border {
217
+ .iroco-ui-form .iroco-ui-input input.border {
218
218
  border: 1px solid var(--form-element-border);
219
219
  }
220
220
  .iroco-ui-form .iroco-ui-label {
@@ -19,7 +19,7 @@
19
19
  display: flex;
20
20
  flex-direction: column;
21
21
 
22
- > input {
22
+ input {
23
23
  color: var(--color-text);
24
24
  background: var(--color-body);
25
25
  border: 1px solid var(--color-border);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iroco/ui",
3
- "version": "1.15.1",
3
+ "version": "1.15.3",
4
4
  "description": "Iroco design system based on Svelte",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {