@v1nt1248/3nclient-lib 0.3.23 → 0.3.24

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.
@@ -2,7 +2,7 @@
2
2
  import { computed, nextTick, onMounted, ref, watch } from 'vue';
3
3
  import Ui3nIcon from '../ui3n-icon/ui3n-icon.vue';
4
4
  import Ui3nButton from '../ui3n-button/ui3n-button.vue';
5
- import type { Ui3nInputEmits, Ui3nInputProps } from './types';
5
+ import type { Ui3nInputEmits, Ui3nInputExpose, Ui3nInputProps, Ui3nInputSlots } from './types';
6
6
 
7
7
  const props = withDefaults(defineProps<Ui3nInputProps>(), {
8
8
  modelValue: '',
@@ -10,19 +10,20 @@
10
10
  size: 'regular',
11
11
  label: '',
12
12
  placeholder: '',
13
- icon: '',
14
- iconColor: '',
15
13
  displayStateMode: undefined,
16
14
  displayStateMessage: '',
17
15
  rules: () => [],
18
16
  clearable: false,
19
17
  autofocus: false,
18
+ readonly: false,
19
+ autocomplete: 'off',
20
20
  validateAtStartup: false,
21
21
  hideBottomSpace: false,
22
22
  displayStateWithIcon: false,
23
23
  disabled: false,
24
24
  });
25
25
  const emits = defineEmits<Ui3nInputEmits>();
26
+ const slots = defineSlots<Ui3nInputSlots>();
26
27
 
27
28
  const inputElement = ref<HTMLInputElement | null>(null);
28
29
  const internalValue = ref('');
@@ -30,12 +31,8 @@
30
31
  const isFocused = ref(false);
31
32
  const errorMessage = ref('');
32
33
 
33
- const cssIconColor = computed(() => {
34
- if (props.disabled) {
35
- return 'var(--color-icon-control-primary-disabled)';
36
- }
37
- return props.iconColor || 'var(--color-icon-control-primary-default)';
38
- });
34
+ const hasPrependIcon = computed(() => !!slots['prepend-icon']);
35
+ const hasAppendIcon = computed(() => !!slots['append-icon']);
39
36
 
40
37
  const showSuccessIcon = computed(
41
38
  () => props.displayStateMode === 'success' && props.displayStateWithIcon && !isFocused.value,
@@ -45,6 +42,8 @@
45
42
  () => !props.disabled && props.clearable && !!internalValue.value && !showSuccessIcon.value,
46
43
  );
47
44
 
45
+ const hasAppendElements = computed(() => showSuccessIcon.value || showClearButton.value || hasAppendIcon.value);
46
+
48
47
  const showMessageBlock = computed(
49
48
  () => !!errorMessage.value || !!(props.displayStateMode && props.displayStateMessage),
50
49
  );
@@ -141,7 +140,8 @@
141
140
  emits('update:valid', true);
142
141
  }
143
142
 
144
- defineExpose({
143
+ defineExpose<Ui3nInputExpose>({
144
+ inputElement,
145
145
  isDirty,
146
146
  isFocused,
147
147
  clearValue,
@@ -186,8 +186,6 @@
186
186
  size === 'large' && $style.large,
187
187
  label && $style.withLabel,
188
188
  hideBottomSpace && $style.withoutBottomSpace,
189
- icon && $style.withIcon,
190
- clearable && internalValue && $style.clearable,
191
189
  disabled && $style.disabled,
192
190
  (!!errorMessage || displayStateMode === 'error') && $style.error,
193
191
  displayStateMode === 'success' && $style.success,
@@ -200,50 +198,68 @@
200
198
  {{ label }}
201
199
  </label>
202
200
 
203
- <input
204
- ref="inputElement"
205
- autocomplete="off"
206
- :type="type"
207
- :placeholder="placeholder"
208
- :disabled="disabled"
209
- :class="$style.ui3nInputField"
210
- @input="onInput"
211
- @keydown.enter="onEnterKeydown"
212
- @keydown.esc="onEscapeKeydown"
213
- @keydown="onKeydown"
214
- @focusin="onFocus"
215
- @focusout="onBlur"
216
- @change="onChange"
217
- />
218
-
219
- <ui3n-icon
220
- v-if="icon"
221
- :icon="icon"
222
- :size="16"
223
- :class="[$style.ui3nInputIcon, disabled && $style.ui3nInputIconDisabled]"
224
- />
225
-
226
- <ui3n-icon
227
- v-if="showSuccessIcon"
228
- icon="round-check-circle-outline"
229
- :size="16"
230
- color="var(--success-content-default)"
231
- :class="$style.ui3nInputSuccessIcon"
232
- />
233
-
234
- <ui3n-button
235
- v-if="showClearButton"
236
- type="icon"
237
- size="small"
238
- color="transparent"
239
- icon="round-close"
240
- icon-size="16"
241
- icon-color="var(--color-icon-control-accent-default)"
242
- :class="$style.clearBtn"
243
- @mousedown.prevent
244
- @touchstart.prevent
245
- @click="clearValue"
246
- />
201
+ <div
202
+ :class="[$style.inputWrapper, hasPrependIcon && $style.withPrepend, hasAppendElements && $style.withAppend]"
203
+ >
204
+ <div
205
+ v-if="hasPrependIcon"
206
+ :class="$style.prependIconSlot"
207
+ >
208
+ <slot name="prepend-icon" />
209
+ </div>
210
+
211
+ <input
212
+ ref="inputElement"
213
+ :autocomplete="autocomplete"
214
+ :type="type"
215
+ :placeholder="placeholder"
216
+ :disabled="disabled"
217
+ :readonly="readonly"
218
+ :name="name"
219
+ :maxlength="maxlength"
220
+ :minlength="minlength"
221
+ :class="$style.ui3nInputField"
222
+ @input="onInput"
223
+ @keydown.enter="onEnterKeydown"
224
+ @keydown.esc="onEscapeKeydown"
225
+ @keydown="onKeydown"
226
+ @focus="onFocus"
227
+ @blur="onBlur"
228
+ @change="onChange"
229
+ />
230
+
231
+ <div
232
+ v-if="hasAppendElements"
233
+ :class="$style.appendIconSlot"
234
+ >
235
+ <ui3n-icon
236
+ v-if="showSuccessIcon"
237
+ icon="round-check-circle-outline"
238
+ :size="16"
239
+ color="var(--success-content-default)"
240
+ :class="$style.appendSlotItem"
241
+ />
242
+
243
+ <ui3n-button
244
+ v-if="showClearButton"
245
+ type="icon"
246
+ size="small"
247
+ color="transparent"
248
+ icon="round-close"
249
+ icon-size="16"
250
+ icon-color="var(--color-icon-control-accent-default)"
251
+ :class="$style.appendSlotItem"
252
+ @mousedown.prevent
253
+ @touchstart.prevent
254
+ @click="clearValue"
255
+ />
256
+
257
+ <slot
258
+ v-if="hasAppendIcon"
259
+ name="append-icon"
260
+ />
261
+ </div>
262
+ </div>
247
263
 
248
264
  <div
249
265
  v-if="showMessageBlock"
@@ -261,95 +277,92 @@
261
277
  <style lang="scss" module>
262
278
  .ui3nInput {
263
279
  --ui3n-input-height: 32px;
264
- --ui3n-input-font-size: var(--font-13);
280
+ --ui3n-input-label-font-size: 12px;
281
+ --ui3n-input-font-size: 13px;
282
+ --ui3n-input-message-font-size: 10px;
265
283
  --ui3n-input-border-radius: var(--spacing-xs);
266
- --ui3n-input-padding-left: var(--spacing-s);
267
- --ui3n-input-padding-right: var(--spacing-s);
268
- --ui3n-input-icon-size: 16px;
269
- --ui3n-input-label-offset: calc(var(--font-16) + var(--spacing-xs));
270
- --ui3n-input-message-top: calc(var(--ui3n-input-height) + var(--ui3n-input-label-offset) + 2px);
271
-
272
- &:not(.withLabel) {
273
- --ui3n-input-label-offset: 0;
284
+ --ui3n-input-padding-x: 8px;
285
+ --ui3n-input-message-top: calc(var(--ui3n-input-height) + var(--spacing-m) + 2px);
286
+ --ui3n-input-outer-padding-top: 1px;
287
+ --ui3n-input-outer-padding-bottom: 15px;
288
+ --ui3n-input-outer-padding-x: 1px;
289
+
290
+ &.withLabel {
291
+ --ui3n-input-message-top: calc(
292
+ var(--ui3n-input-height) + calc(var(--ui3n-input-label-font-size) * 1.33) + 6px
293
+ );
274
294
  }
275
295
 
276
296
  &.large {
277
297
  --ui3n-input-height: 48px;
278
- --ui3n-input-font-size: var(--font-16);
298
+ --ui3n-input-font-size: 16px;
279
299
  --ui3n-input-border-radius: 8px;
280
- --ui3n-input-padding-left: 12px;
281
- --ui3n-input-padding-right: 12px;
282
-
283
- .clearBtn {
284
- right: 2px;
285
- }
286
-
287
- &.withIcon {
288
- .ui3nInputIcon {
289
- left: 6px;
290
- }
291
- }
300
+ --ui3n-input-padding-x: 12px;
292
301
  }
293
302
 
294
303
  position: relative;
295
304
  width: 100%;
296
- padding: 1px 1px 15px 1px;
305
+ padding: var(--ui3n-input-outer-padding-top) var(--ui3n-input-outer-padding-x)
306
+ var(--ui3n-input-outer-padding-bottom) var(--ui3n-input-outer-padding-x);
297
307
  border-radius: var(--ui3n-input-border-radius);
298
308
 
299
309
  &.withoutBottomSpace {
300
- padding-bottom: 0;
310
+ --ui3n-input-outer-padding-bottom: 0;
301
311
  }
302
312
 
303
313
  &:hover {
304
- .ui3nInputField:not(:focus-within) {
314
+ .inputWrapper:not(:focus-within) {
305
315
  background-color: var(--color-bg-control-secondary-hover);
306
316
 
307
- &::placeholder {
317
+ .ui3nInputField::placeholder {
308
318
  color: var(--color-text-control-secondary-hover);
309
319
  }
310
320
  }
311
321
  }
312
322
 
313
323
  &:focus-within {
314
- .ui3nInputField {
324
+ .inputWrapper {
315
325
  background-color: var(--color-bg-control-secondary-focused);
316
326
  outline: 1px solid var(--color-border-control-accent-focused);
317
327
  }
318
-
319
- .ui3nInputIcon {
320
- color: v-bind(cssIconColor);
321
- }
322
328
  }
323
329
  }
324
330
 
325
331
  .ui3nInputLabel {
326
332
  display: block;
327
333
  width: 100%;
328
- font-size: var(--font-12);
329
- line-height: var(--font-16);
334
+ font-size: var(--ui3n-input-label-font-size);
335
+ line-height: 1.33;
330
336
  font-weight: 500;
331
337
  color: var(--color-text-control-primary-default);
332
- margin-bottom: var(--spacing-xs);
338
+ margin-bottom: 4px;
339
+ }
340
+
341
+ .inputWrapper {
342
+ display: flex;
343
+ align-items: center;
344
+ height: var(--ui3n-input-height);
345
+ border-radius: var(--ui3n-input-border-radius);
346
+ background-color: var(--color-bg-control-secondary-default);
347
+ transition: background-color 0.2s ease-in-out;
333
348
  }
334
349
 
335
350
  .ui3nInputField {
351
+ flex: 1;
352
+ min-width: 0;
336
353
  display: block;
337
354
  box-sizing: border-box;
338
355
  width: 100%;
339
- position: relative;
340
356
  border: none;
341
357
  outline: none;
342
- height: var(--ui3n-input-height);
343
- padding: 0 var(--ui3n-input-padding-right) 0 var(--ui3n-input-padding-left);
344
- border-radius: var(--ui3n-input-border-radius);
345
- background-color: var(--color-bg-control-secondary-default);
358
+ height: 100%;
359
+ padding: 0 var(--ui3n-input-padding-x);
360
+ background-color: transparent;
346
361
  font-size: var(--ui3n-input-font-size);
347
362
  line-height: var(--spacing-m);
348
363
  font-weight: 400;
349
364
  color: var(--color-text-control-primary-default);
350
- transition:
351
- background-color 0.2s ease-in-out,
352
- color 0.2s ease-in-out;
365
+ transition: color 0.2s ease-in-out;
353
366
 
354
367
  &::placeholder {
355
368
  color: var(--color-text-control-secondary-default);
@@ -363,27 +376,44 @@
363
376
  }
364
377
 
365
378
  &[disabled] {
366
- background-color: var(--color-bg-control-secondary-disabled);
367
379
  color: var(--color-text-control-secondary-disabled);
380
+ cursor: not-allowed;
381
+ }
382
+
383
+ &[readonly] {
384
+ cursor: default;
368
385
  }
369
386
  }
370
387
 
371
- .ui3nInputIcon {
372
- position: absolute;
373
- left: var(--spacing-xs);
374
- top: calc((var(--ui3n-input-height) - var(--ui3n-input-icon-size)) / 2);
375
- color: var(--color-icon-control-secondary-default);
388
+ .prependIconSlot {
389
+ display: flex;
390
+ align-items: center;
391
+ flex-shrink: 0;
392
+ padding-left: calc(var(--ui3n-input-padding-x) / 2);
376
393
  }
377
394
 
378
- .ui3nInputIconDisabled {
379
- color: v-bind(cssIconColor);
395
+ .appendIconSlot {
396
+ display: flex;
397
+ align-items: center;
398
+ flex-shrink: 0;
399
+ gap: 4px;
400
+ padding-right: calc(var(--ui3n-input-padding-x) / 2);
380
401
  }
381
402
 
382
- .clearBtn {
383
- position: absolute;
384
- right: 0;
385
- top: calc((var(--ui3n-input-height) - 24px) / 2);
386
- z-index: 2;
403
+ .withPrepend {
404
+ .ui3nInputField {
405
+ padding-left: calc(var(--ui3n-input-padding-x) / 2);
406
+ }
407
+ }
408
+
409
+ .withAppend {
410
+ .ui3nInputField {
411
+ padding-right: calc(var(--ui3n-input-padding-x) / 2);
412
+ }
413
+ }
414
+
415
+ .appendSlotItem {
416
+ flex-shrink: 0;
387
417
  }
388
418
 
389
419
  .ui3nInputFieldMessage {
@@ -392,9 +422,9 @@
392
422
  width: 100%;
393
423
  top: calc(var(--ui3n-input-message-top) + 2px);
394
424
  font-style: italic;
395
- font-size: var(--font-10);
425
+ font-size: var(--ui3n-input-message-font-size);
396
426
  font-weight: 400;
397
- line-height: 1.1;
427
+ line-height: 1.2;
398
428
  }
399
429
 
400
430
  .ui3nInputErrorMessage {
@@ -405,28 +435,12 @@
405
435
  color: var(--success-content-default);
406
436
  }
407
437
 
408
- .clearable {
409
- --ui3n-input-padding-right: var(--spacing-ml);
410
-
411
- &.large {
412
- --ui3n-input-padding-right: calc(var(--spacing-ml) + 4px);
413
- }
414
- }
415
-
416
- .withIcon {
417
- --ui3n-input-padding-left: var(--spacing-ml);
418
-
419
- &.large {
420
- --ui3n-input-padding-left: calc(var(--spacing-ml) + 4px);
421
- }
422
- }
423
-
424
438
  .error {
425
439
  .ui3nInputLabel {
426
440
  color: var(--error-content-default);
427
441
  }
428
442
 
429
- .ui3nInputField {
443
+ .inputWrapper {
430
444
  outline: 1px solid var(--error-content-default);
431
445
  }
432
446
  }
@@ -437,30 +451,13 @@
437
451
  }
438
452
  }
439
453
 
440
- .ui3nInputSuccessIcon {
441
- position: absolute;
442
- right: var(--spacing-s);
443
- bottom: var(--spacing-s);
444
- }
445
-
446
454
  .disabled {
447
455
  pointer-events: none;
448
456
  user-select: none;
449
- }
450
-
451
- .withLabel {
452
- .ui3nInputIcon {
453
- top: calc((var(--ui3n-input-height) - var(--ui3n-input-icon-size)) / 2 + var(--ui3n-input-label-offset));
454
- }
455
457
 
456
- .ui3nInputSuccessIcon {
457
- bottom: auto;
458
- top: calc((var(--ui3n-input-height) - var(--ui3n-input-icon-size)) / 2 + var(--ui3n-input-label-offset));
459
- }
460
-
461
- .clearBtn {
462
- top: calc((var(--ui3n-input-height) - 24px) / 2 + var(--ui3n-input-label-offset));
463
- z-index: 1;
458
+ .inputWrapper {
459
+ background-color: var(--color-bg-control-secondary-disabled);
460
+ cursor: not-allowed;
464
461
  }
465
462
  }
466
463
  </style>