@inglorious/ui 7.2.1 → 7.2.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.
@@ -21,66 +21,9 @@ import {
21
21
 
22
22
  const NO_FOCUSED_INDEX = -1
23
23
 
24
- /**
25
- * Registered outside-pointer listeners, keyed by the dropdown element they
26
- * belong to. Used only to deduplicate: the ref callback is handed a fresh arrow
27
- * on every re-render, so without this each pass would stack another listener on
28
- * the document.
29
- * @type {WeakMap<Element, { props: ComboboxProps, listener: (event: Event) => void }>}
30
- */
31
- const outsideListeners = new WeakMap()
32
-
33
- /**
34
- * Listen on the document for presses outside the dropdown, closing it when one
35
- * happens.
36
- *
37
- * This listens for `pointerdown` rather than `click` on purpose. Mobile browsers
38
- * synthesise `click` asynchronously after `touchend`, and drop it entirely when
39
- * the touch drifts into a scroll gesture or the target is replaced meanwhile.
40
- * A suppressed click would leave the listener armed, and it would then close the
41
- * *next* dropdown on the tap that opened it, leaving the combobox looking stuck.
42
- * `pointerdown` is dispatched synchronously for mouse, touch and pen.
43
- *
44
- * No id is needed: the element keys the listener, and it retires itself once its
45
- * dropdown has left the DOM.
46
- * @param {ComboboxProps} props
47
- * @param {Element|null|undefined} el dropdown element, or undefined on unmount
48
- */
49
- function trackOutsideClick(props, el) {
50
- if (!el) return
51
-
52
- const existing = outsideListeners.get(el)
53
- if (existing) {
54
- // A re-render of the same dropdown: keep the one listener, but point it at
55
- // the current props so onClose is not captured from the first render.
56
- existing.props = props
57
- return
58
- }
59
-
60
- const entry = { props }
61
- entry.listener = (event) => {
62
- // The dropdown left the DOM: this press is the last one to hear from it.
63
- // Retiring here is what keeps a torn-down dropdown from closing whatever
64
- // opens next.
65
- if (!el.isConnected) {
66
- document.removeEventListener("pointerdown", entry.listener)
67
- return
68
- }
69
-
70
- // The root, not the dropdown: the control is a sibling of the dropdown, and a
71
- // press on it has to count as inside. Resolved per event rather than at mount
72
- // because the dropdown is not connected yet when the ref first runs.
73
- const root = el.closest(".iw-combobox") ?? el
74
- if (!event.composedPath().includes(root)) entry.props.onClose?.()
75
- }
76
-
77
- outsideListeners.set(el, entry)
78
- document.addEventListener("pointerdown", entry.listener)
79
- }
80
-
81
24
  export const Combobox = {
82
25
  /**
83
- * Main entrypoint for the combobox control. It renders the wrapper, label, control, and dropdown when open.
26
+ * Main entrypoint for the combobox control. It renders the frame, label, control, and dropdown when open.
84
27
  * Comboboxes support search, single or multi-select values, and clearable selection.
85
28
  * @param {ComboboxProps} props
86
29
  * @returns {TemplateResult}
@@ -90,26 +33,63 @@ export const Combobox = {
90
33
  },
91
34
 
92
35
  /**
93
- * Main entrypoint for the combobox control. It renders the wrapper, label, control, and dropdown when open.
36
+ * Main entrypoint for the combobox control. It renders the frame, label, control, and dropdown when open.
94
37
  * Comboboxes support search, single or multi-select values, and clearable selection.
95
38
  * @param {ComboboxProps} props
96
39
  * @returns {TemplateResult}
97
40
  */
98
41
  renderCombobox(props) {
99
- return html`<div
100
- class=${classMap({
101
- "iw-combobox": true,
102
- "iw-combobox-full-width": !!props.isFullWidth,
103
- [`iw-combobox-${props.size}`]: props.size !== "md",
104
- })}
105
- >
106
- ${
107
- props.label
108
- ? html`<label class="iw-combobox-label">${props.label}</label>`
109
- : null
110
- }
111
- ${this.renderControl?.(props)}
112
- ${when(props.isOpen, () => this.renderDropdown?.(props))}
42
+ const {
43
+ id,
44
+ type, // eslint-disable-line no-unused-vars
45
+ label,
46
+ hint,
47
+ error,
48
+ isRequired = false,
49
+ isFullWidth = false,
50
+ isOpen = false,
51
+ } = props
52
+ // The control is a div, not a labellable element, so a `for` binding is not
53
+ // available. It is referenced by id from the control's aria-labelledby
54
+ // instead, which is what a screen reader actually reads here.
55
+ // Only minted when there is something to point at. A reference to an id
56
+ // that is not in the DOM is worse than no reference at all.
57
+ const labelId = label && id ? `${id}-label` : ""
58
+ const messageId = (error || hint) && id ? `${id}-message` : ""
59
+
60
+ const comboboxClasses = {
61
+ "iw-combobox": true,
62
+ "iw-combobox-full-width": !!isFullWidth,
63
+ }
64
+
65
+ return html`<div class=${classMap(comboboxClasses)}>
66
+ ${when(
67
+ label,
68
+ () =>
69
+ html`<label id=${labelId || ""} class="iw-combobox-label">
70
+ ${label}
71
+ ${when(
72
+ isRequired,
73
+ () => html`<span class="iw-combobox-required">*</span>`,
74
+ )}
75
+ </label>`,
76
+ )}
77
+ ${this.renderControl?.({ ...props, labelId, messageId })}
78
+ ${when(isOpen, () => this.renderDropdown?.(props))}
79
+ ${when(
80
+ error,
81
+ () =>
82
+ html`<span id=${messageId ?? ""} class="iw-combobox-error-message"
83
+ >${error}</span
84
+ >`,
85
+ )}
86
+ ${when(
87
+ !error && hint,
88
+ () =>
89
+ html`<span id=${messageId || ""} class="iw-combobox-hint"
90
+ >${hint}</span
91
+ >`,
92
+ )}
113
93
  </div>`
114
94
  },
115
95
 
@@ -125,50 +105,72 @@ export const Combobox = {
125
105
  * @returns {TemplateResult}
126
106
  */
127
107
  renderControl(props) {
128
- const controlId = props.id ? `${props.id}-control` : undefined
108
+ const {
109
+ id,
110
+ labelId,
111
+ messageId,
112
+ selectedValue,
113
+ error,
114
+ size = "md",
115
+ isDisabled = false,
116
+ isRequired = false,
117
+ isOpen = false,
118
+ isMulti = false,
119
+ isClearable = false,
120
+ onToggle,
121
+ onClear,
122
+ } = props
123
+
124
+ const controlId = id ? `${id}-control` : ""
125
+
126
+ const frameClasses = {
127
+ "iw-combobox-frame": true,
128
+ [`iw-combobox-${size}`]: true,
129
+ "iw-combobox-frame-open": isOpen,
130
+ "iw-combobox-frame-disabled": isDisabled,
131
+ "iw-combobox-frame-error": !!error,
132
+ "iw-combobox-frame-selection":
133
+ isMulti && Array.isArray(selectedValue) && selectedValue.length,
134
+ }
135
+
129
136
  return html`<div
130
- id=${controlId ?? ""}
131
- class="iw-combobox-control ${classMap({
132
- "iw-combobox-control-open": props.isOpen,
133
- "iw-combobox-control-disabled": props.isDisabled,
134
- "iw-combobox-control-selection":
135
- props.isMulti &&
136
- Array.isArray(props.selectedValue) &&
137
- props.selectedValue.length,
138
- })}"
137
+ id=${controlId}
138
+ class="${classMap(frameClasses)}"
139
139
  role="combobox"
140
140
  aria-haspopup="listbox"
141
- aria-expanded=${props.isOpen ? "true" : "false"}
141
+ aria-expanded=${isOpen ? "true" : "false"}
142
142
  aria-controls=${controlId ? `${controlId}-listbox` : ""}
143
- tabindex=${props.isDisabled ? -1 : 0}
143
+ aria-labelledby=${labelId || ""}
144
+ aria-describedby=${messageId || ""}
145
+ aria-required=${isRequired ? "true" : "false"}
146
+ aria-invalid=${error ? "true" : "false"}
147
+ tabindex=${isDisabled ? -1 : 0}
144
148
  @keydown=${(event) => handleControlKeyDown(props, event)}
145
- @click=${() => !props.isDisabled && props.onToggle?.()}
149
+ @click=${() => !isDisabled && onToggle?.()}
146
150
  >
147
151
  ${when(
148
- props.isMulti,
152
+ isMulti,
149
153
  () => this.renderMultiValue?.(props),
150
154
  () => this.renderSingleValue?.(props),
151
155
  )}
152
156
  ${when(
153
- props.isClearable &&
154
- ((props.isMulti &&
155
- Array.isArray(props.selectedValue) &&
156
- props.selectedValue.length) ||
157
- (!props.isMulti && props.selectedValue !== null)),
157
+ isClearable &&
158
+ ((isMulti && Array.isArray(selectedValue) && selectedValue.length) ||
159
+ (!isMulti && selectedValue !== null)),
158
160
  () =>
159
161
  html`<button
160
162
  class="iw-combobox-clear"
161
163
  type="button"
162
164
  @click=${(event) => {
163
165
  event.stopPropagation()
164
- props.onClear?.()
166
+ onClear?.()
165
167
  }}
166
168
  >
167
169
  ×
168
170
  </button>`,
169
171
  )}
170
172
 
171
- <div class="iw-combobox-arrow"><span>▼</span></div>
173
+ <span class="iw-combobox-arrow" aria-hidden="true">▼</span>
172
174
  </div>`
173
175
  },
174
176
 
@@ -179,21 +181,21 @@ export const Combobox = {
179
181
  * @returns {TemplateResult}
180
182
  */
181
183
  renderSingleValue(props) {
182
- if (props.selectedValue === null) {
183
- return html`<span class="iw-combobox-placeholder"
184
- >${props.placeholder}</span
184
+ const { options, selectedValue, placeholder } = props
185
+
186
+ if (selectedValue === null) {
187
+ return html`<span class="iw-combobox-control iw-combobox-placeholder"
188
+ >${placeholder}</span
185
189
  >`
186
190
  }
187
191
 
188
- const selectedOption = props.options.find(
189
- (option) => getOptionValue(option) === props.selectedValue,
192
+ const selectedOption = options.find(
193
+ (option) => getOptionValue(option) === selectedValue,
190
194
  )
191
195
 
192
- return html`<span class="iw-combobox-value"
196
+ return html`<span class="iw-combobox-control iw-combobox-value"
193
197
  >${
194
- selectedOption
195
- ? getOptionLabel(selectedOption)
196
- : String(props.selectedValue)
198
+ selectedOption ? getOptionLabel(selectedOption) : String(selectedValue)
197
199
  }</span
198
200
  >`
199
201
  },
@@ -205,15 +207,17 @@ export const Combobox = {
205
207
  * @returns {TemplateResult}
206
208
  */
207
209
  renderMultiValue(props) {
208
- if (!Array.isArray(props.selectedValue) || !props.selectedValue.length) {
209
- return html`<span class="iw-combobox-placeholder"
210
- >${props.placeholder}</span
210
+ const { selectedValue, placeholder } = props
211
+
212
+ if (!Array.isArray(selectedValue) || !selectedValue.length) {
213
+ return html`<span class="iw-combobox-control iw-combobox-placeholder"
214
+ >${placeholder}</span
211
215
  >`
212
216
  }
213
217
 
214
- return html`<div class="iw-combobox-multi-value">
218
+ return html`<div class="iw-combobox-control iw-combobox-multi-value">
215
219
  ${repeat(
216
- props.selectedValue,
220
+ selectedValue,
217
221
  (value) => value,
218
222
  (value) => this.renderMultiValueTag?.(props, value),
219
223
  )}
@@ -228,9 +232,11 @@ export const Combobox = {
228
232
  * @returns {TemplateResult}
229
233
  */
230
234
  renderMultiValueTag(props, value) {
231
- const option = props.options.find((opt) => getOptionValue(opt) === value)
232
- const tagId = `${props.id}-tag-${String(value)}`
233
- const chipSize = props.size === "lg" ? "md" : "sm"
235
+ const { id, options, size, onOptionSelect, onChange } = props
236
+
237
+ const option = options.find((opt) => getOptionValue(opt) === value)
238
+ const tagId = `${id}-tag-${String(value)}`
239
+ const chipSize = size === "lg" ? "md" : "sm"
234
240
 
235
241
  return html`<span
236
242
  class="iw-combobox-multi-value-tag"
@@ -243,8 +249,8 @@ export const Combobox = {
243
249
  size: chipSize,
244
250
  shape: "rounded",
245
251
  onClick: () => {
246
- props.onOptionSelect?.(option)
247
- props.onChange?.(option)
252
+ onOptionSelect?.(option)
253
+ onChange?.(option)
248
254
  },
249
255
  })}
250
256
  </span>`
@@ -257,20 +263,22 @@ export const Combobox = {
257
263
  * @returns {TemplateResult}
258
264
  */
259
265
  renderDropdown(props) {
260
- const filteredOptions = filterOptions(props.options, props.searchTerm)
266
+ const { id, options, searchTerm, isSearchable, isLoading } = props
267
+
268
+ const filteredOptions = filterOptions(options, searchTerm)
261
269
 
262
270
  return html`<div
263
- id=${props.id ? `${props.id}-control-listbox` : ""}
271
+ id=${id ? `${id}-control-listbox` : ""}
264
272
  class="iw-combobox-dropdown"
265
273
  role="listbox"
266
274
  ${ref((el) => trackOutsideClick(props, el))}
267
275
  >
268
- ${when(props.isSearchable, () => this.renderSearchInput?.(props))}
269
- ${when(props.isLoading, () => this.renderLoading?.(props))}
270
- ${when(!props.isLoading && !filteredOptions.length, () =>
276
+ ${when(isSearchable, () => this.renderSearchInput?.(props))}
277
+ ${when(isLoading, () => this.renderLoading?.(props))}
278
+ ${when(!isLoading && !filteredOptions.length, () =>
271
279
  this.renderNoOptions?.(props),
272
280
  )}
273
- ${when(!props.isLoading && filteredOptions.length, () =>
281
+ ${when(!isLoading && filteredOptions.length, () =>
274
282
  this.renderOptions?.(props),
275
283
  )}
276
284
  </div>`
@@ -283,15 +291,17 @@ export const Combobox = {
283
291
  * @returns {TemplateResult}
284
292
  */
285
293
  renderSearchInput(props) {
294
+ const { searchTerm, isOpen, onSearchChange } = props
295
+
286
296
  return html`<input
287
297
  class="iw-combobox-dropdown-search"
288
298
  type="text"
289
299
  placeholder="Search..."
290
- .value=${props.searchTerm ?? ""}
291
- @input=${(event) => props.onSearchChange?.(event.target.value)}
300
+ .value=${searchTerm ?? ""}
301
+ @input=${(event) => onSearchChange?.(event.target.value)}
292
302
  @keydown=${(event) => handleKeyDown(props, event)}
293
303
  ${ref((el) => {
294
- if (el && props.isOpen) queueMicrotask(() => el.focus())
304
+ if (el && isOpen) queueMicrotask(() => el.focus())
295
305
  })}
296
306
  />`
297
307
  },
@@ -303,7 +313,9 @@ export const Combobox = {
303
313
  * @returns {TemplateResult}
304
314
  */
305
315
  renderOptions(props) {
306
- const filteredOptions = filterOptions(props.options, props.searchTerm)
316
+ const { options, searchTerm } = props
317
+
318
+ const filteredOptions = filterOptions(options, searchTerm)
307
319
 
308
320
  return html`<div class="iw-combobox-dropdown-options">
309
321
  ${repeat(
@@ -322,16 +334,22 @@ export const Combobox = {
322
334
  * @returns {TemplateResult}
323
335
  */
324
336
  renderOption(props, { option, index }) {
337
+ const {
338
+ id,
339
+ selectedValue,
340
+ focusedIndex,
341
+ isMulti,
342
+ onOptionSelect,
343
+ onChange,
344
+ onFocusSet,
345
+ } = props
346
+
325
347
  const normalized = formatOption(option)
326
- const isSelected = isOptionSelected(
327
- option,
328
- props.selectedValue,
329
- props.isMulti,
330
- )
331
- const isFocused = index === props.focusedIndex
348
+ const isSelected = isOptionSelected(option, selectedValue, isMulti)
349
+ const isFocused = index === focusedIndex
332
350
 
333
351
  return html`<div
334
- id=${props.id ? `${props.id}-option-${index}` : ""}
352
+ id=${id ? `${id}-option-${index}` : ""}
335
353
  role="option"
336
354
  aria-selected=${isSelected ? "true" : "false"}
337
355
  class="iw-combobox-dropdown-options-option ${classMap({
@@ -341,13 +359,13 @@ export const Combobox = {
341
359
  })}"
342
360
  @click=${() => {
343
361
  if (normalized.isDisabled) return
344
- props.onOptionSelect?.(normalized)
345
- props.onChange?.(normalized)
362
+ onOptionSelect?.(normalized)
363
+ onChange?.(normalized)
346
364
  }}
347
- @mouseenter=${() => props.onFocusSet?.(index)}
365
+ @mouseenter=${() => onFocusSet?.(index)}
348
366
  >
349
367
  ${when(
350
- props.isMulti,
368
+ isMulti,
351
369
  () =>
352
370
  html`<input
353
371
  type="checkbox"
@@ -366,7 +384,9 @@ export const Combobox = {
366
384
  * @returns {TemplateResult}
367
385
  */
368
386
  renderLoading(props) {
369
- return html`<div class="iw-combobox-loading">${props.loadingMessage}</div>`
387
+ const { loadingMessage } = props
388
+
389
+ return html`<div class="iw-combobox-loading">${loadingMessage}</div>`
370
390
  },
371
391
 
372
392
  /**
@@ -376,9 +396,8 @@ export const Combobox = {
376
396
  * @returns {TemplateResult}
377
397
  */
378
398
  renderNoOptions(props) {
379
- return html`<div class="iw-combobox-no-options">
380
- ${props.noOptionsMessage}
381
- </div>`
399
+ const { noOptionsMessage } = props
400
+ return html`<div class="iw-combobox-no-options">${noOptionsMessage}</div>`
382
401
  },
383
402
  }
384
403
 
@@ -392,9 +411,11 @@ export const Combobox = {
392
411
  * @param {KeyboardEvent} event
393
412
  */
394
413
  function handleControlKeyDown(props, event) {
395
- if (props.isDisabled) return
414
+ const { isDisabled, isOpen, onToggle } = props
415
+
416
+ if (isDisabled) return
396
417
 
397
- if (props.isOpen) {
418
+ if (isOpen) {
398
419
  handleKeyDown(props, event)
399
420
  return
400
421
  }
@@ -404,7 +425,7 @@ function handleControlKeyDown(props, event) {
404
425
  }
405
426
  // Space would otherwise scroll the page out from under the dropdown.
406
427
  event.preventDefault()
407
- props.onToggle?.()
428
+ onToggle?.()
408
429
  }
409
430
 
410
431
  /**
@@ -413,43 +434,110 @@ function handleControlKeyDown(props, event) {
413
434
  * @param {KeyboardEvent} event
414
435
  */
415
436
  function handleKeyDown(props, event) {
416
- const filteredOptions = filterOptions(props.options, props.searchTerm)
437
+ const {
438
+ options,
439
+ searchTerm,
440
+ focusedIndex,
441
+ onFocusFirst,
442
+ onFocusPrev,
443
+ onFocusNext,
444
+ onFocusLast,
445
+ onOptionSelect,
446
+ onChange,
447
+ onClose,
448
+ } = props
449
+
450
+ const filteredOptions = filterOptions(options, searchTerm)
417
451
 
418
452
  switch (event.key) {
419
453
  case "ArrowDown":
420
454
  event.preventDefault()
421
- props.onFocusNext?.()
455
+ onFocusNext?.()
422
456
  break
423
457
  case "ArrowUp":
424
458
  event.preventDefault()
425
- props.onFocusPrev?.()
459
+ onFocusPrev?.()
426
460
  break
427
461
  case "Enter":
428
462
  event.preventDefault()
429
- if (
430
- props.focusedIndex > NO_FOCUSED_INDEX &&
431
- filteredOptions[props.focusedIndex]
432
- ) {
433
- const option = formatOption(filteredOptions[props.focusedIndex])
463
+ if (focusedIndex > NO_FOCUSED_INDEX && filteredOptions[focusedIndex]) {
464
+ const option = formatOption(filteredOptions[focusedIndex])
434
465
  if (!option.isDisabled) {
435
- props.onOptionSelect?.(option)
436
- props.onChange?.(option)
466
+ onOptionSelect?.(option)
467
+ onChange?.(option)
437
468
  }
438
469
  }
439
470
  break
440
471
  case "Escape":
441
472
  event.preventDefault()
442
- props.onClose?.()
473
+ onClose?.()
443
474
  break
444
475
  case "Home":
445
476
  event.preventDefault()
446
- props.onFocusFirst?.()
477
+ onFocusFirst?.()
447
478
  break
448
479
  case "End":
449
480
  event.preventDefault()
450
- props.onFocusLast?.()
481
+ onFocusLast?.()
451
482
  break
452
483
  default:
453
484
  break
454
485
  }
455
486
  }
487
+
488
+ /**
489
+ * Registered outside-pointer listeners, keyed by the dropdown element they
490
+ * belong to. Used only to deduplicate: the ref callback is handed a fresh arrow
491
+ * on every re-render, so without this each pass would stack another listener on
492
+ * the document.
493
+ * @type {WeakMap<Element, { props: ComboboxProps, listener: (event: Event) => void }>}
494
+ */
495
+ const outsideListeners = new WeakMap()
496
+
497
+ /**
498
+ * Listen on the document for presses outside the dropdown, closing it when one
499
+ * happens.
500
+ *
501
+ * This listens for `pointerdown` rather than `click` on purpose. Mobile browsers
502
+ * synthesise `click` asynchronously after `touchend`, and drop it entirely when
503
+ * the touch drifts into a scroll gesture or the target is replaced meanwhile.
504
+ * A suppressed click would leave the listener armed, and it would then close the
505
+ * *next* dropdown on the tap that opened it, leaving the combobox looking stuck.
506
+ * `pointerdown` is dispatched synchronously for mouse, touch and pen.
507
+ *
508
+ * No id is needed: the element keys the listener, and it retires itself once its
509
+ * dropdown has left the DOM.
510
+ * @param {ComboboxProps} props
511
+ * @param {Element|null|undefined} el dropdown element, or undefined on unmount
512
+ */
513
+ function trackOutsideClick(props, el) {
514
+ if (!el) return
515
+
516
+ const existing = outsideListeners.get(el)
517
+ if (existing) {
518
+ // A re-render of the same dropdown: keep the one listener, but point it at
519
+ // the current props so onClose is not captured from the first render.
520
+ existing.props = props
521
+ return
522
+ }
523
+
524
+ const entry = { props }
525
+ entry.listener = (event) => {
526
+ // The dropdown left the DOM: this press is the last one to hear from it.
527
+ // Retiring here is what keeps a torn-down dropdown from closing whatever
528
+ // opens next.
529
+ if (!el.isConnected) {
530
+ document.removeEventListener("pointerdown", entry.listener)
531
+ return
532
+ }
533
+
534
+ // The root, not the dropdown: the control is a sibling of the dropdown, and a
535
+ // press on it has to count as inside. Resolved per event rather than at mount
536
+ // because the dropdown is not connected yet when the ref first runs.
537
+ const root = el.closest(".iw-combobox") ?? el
538
+ if (!event.composedPath().includes(root)) entry.props.onClose?.()
539
+ }
540
+
541
+ outsideListeners.set(el, entry)
542
+ document.addEventListener("pointerdown", entry.listener)
543
+ }
@@ -1,3 +1,3 @@
1
- import * as renderers from "./template.js"
1
+ import { Input as renderers } from "./template.js"
2
2
 
3
3
  export const Input = { ...renderers }
@@ -174,6 +174,25 @@ WithError.args = {
174
174
  error: "Please enter a valid email address",
175
175
  }
176
176
 
177
+ export const WithIcon = {}
178
+ WithIcon.args = {
179
+ ...Default.args,
180
+ icon: "@",
181
+ }
182
+
183
+ export const WithIconAfter = {}
184
+ WithIconAfter.args = {
185
+ ...Default.args,
186
+ iconAfter: "@",
187
+ }
188
+
189
+ export const WithBothIcons = {}
190
+ WithBothIcons.args = {
191
+ ...Default.args,
192
+ icon: "@",
193
+ iconAfter: "@",
194
+ }
195
+
177
196
  export const Required = {}
178
197
  Required.args = {
179
198
  ...Default.args,
@@ -206,6 +225,13 @@ Small.args = {
206
225
  size: "sm",
207
226
  }
208
227
 
228
+ export const Medium = {}
229
+ Medium.args = {
230
+ ...Default.args,
231
+ label: "Medium Input",
232
+ size: "md",
233
+ }
234
+
209
235
  export const Large = {}
210
236
  Large.args = {
211
237
  ...Default.args,
@@ -286,3 +312,12 @@ Color.args = {
286
312
  inputType: "color",
287
313
  value: "#7c3aed",
288
314
  }
315
+
316
+ export const Password = {}
317
+ Password.args = {
318
+ ...Default.args,
319
+ label: "Password",
320
+ inputType: "password",
321
+ placeholder: "••••••••",
322
+ iconAfter: "@",
323
+ }