@volverjs/ui-vue 0.0.10-beta.54 → 0.0.10-beta.56

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.
Files changed (30) hide show
  1. package/auto-imports.d.ts +3 -0
  2. package/dist/components/VvCombobox/VvCombobox.es.js +357 -357
  3. package/dist/components/VvCombobox/VvCombobox.umd.js +1 -1
  4. package/dist/components/VvInputText/VvInputText.es.js +150 -44
  5. package/dist/components/VvInputText/VvInputText.umd.js +1 -1
  6. package/dist/components/VvInputText/VvInputText.vue.d.ts +6 -6
  7. package/dist/components/VvInputText/index.d.ts +1 -1
  8. package/dist/components/VvTextarea/VvTextarea.es.js +966 -67
  9. package/dist/components/VvTextarea/VvTextarea.umd.js +1 -1
  10. package/dist/components/VvTextarea/VvTextarea.vue.d.ts +52 -0
  11. package/dist/components/VvTextarea/index.d.ts +37 -1
  12. package/dist/components/index.es.js +542 -284
  13. package/dist/components/index.umd.js +1 -1
  14. package/dist/icons.es.js +3 -3
  15. package/dist/icons.umd.js +1 -1
  16. package/dist/stories/InputText/InputText.test.d.ts +1 -0
  17. package/dist/stories/InputText/InputTextIso.stories.d.ts +10 -0
  18. package/dist/utils/DateUtilities.d.ts +22 -0
  19. package/package.json +22 -22
  20. package/src/assets/icons/detailed.json +1 -1
  21. package/src/assets/icons/normal.json +1 -1
  22. package/src/assets/icons/simple.json +1 -1
  23. package/src/components/VvCombobox/VvCombobox.vue +3 -3
  24. package/src/components/VvInputText/VvInputText.vue +103 -63
  25. package/src/components/VvInputText/index.ts +1 -1
  26. package/src/components/VvTextarea/VvTextarea.vue +108 -5
  27. package/src/components/VvTextarea/index.ts +32 -1
  28. package/src/stories/InputText/InputText.test.ts +25 -0
  29. package/src/stories/InputText/InputTextIso.stories.ts +69 -0
  30. package/src/utils/DateUtilities.ts +98 -0
@@ -3319,6 +3319,181 @@ const _sfc_main$j = /* @__PURE__ */ defineComponent({
3319
3319
  };
3320
3320
  }
3321
3321
  });
3322
+ const VvComboboxProps = {
3323
+ ...IdNameProps,
3324
+ ...TabindexProps,
3325
+ ...ValidProps,
3326
+ ...InvalidProps,
3327
+ ...HintProps,
3328
+ ...LoadingProps,
3329
+ ...DisabledProps,
3330
+ ...ReadonlyProps,
3331
+ ...ModifiersProps,
3332
+ ...OptionsProps,
3333
+ ...IconProps,
3334
+ ...FloatingLabelProps,
3335
+ ...DropdownProps,
3336
+ ...LabelProps,
3337
+ ...RequiredProps,
3338
+ /**
3339
+ * Dropdown show / hide transition name
3340
+ */
3341
+ transitionName: {
3342
+ type: String,
3343
+ default: "vv-dropdown--mobile-fade-block"
3344
+ },
3345
+ /**
3346
+ * modelValue can be a string, number, boolean, object or array of string, number, boolean, object
3347
+ */
3348
+ modelValue: {
3349
+ type: [String, Number, Boolean, Object, Array],
3350
+ default: void 0
3351
+ },
3352
+ /**
3353
+ * Label for no search results
3354
+ */
3355
+ noResultsLabel: { type: String, default: "No results" },
3356
+ /**
3357
+ * Label for no options available
3358
+ */
3359
+ noOptionsLabel: { type: String, default: "No options available" },
3360
+ /**
3361
+ * Label for selected option hint
3362
+ */
3363
+ selectedHintLabel: { type: String, default: "Selected" },
3364
+ /**
3365
+ * Label for deselect action button
3366
+ */
3367
+ deselectActionLabel: { type: String, default: "Deselect" },
3368
+ /**
3369
+ * Label for select option hint
3370
+ */
3371
+ selectHintLabel: { type: String, default: "Press enter to select" },
3372
+ /**
3373
+ * Label for deselected option hint
3374
+ */
3375
+ deselectHintLabel: { type: String, default: "Press enter to remove" },
3376
+ /**
3377
+ * Label close button
3378
+ */
3379
+ closeLabel: { type: String, default: "Close" },
3380
+ /**
3381
+ * Select input placeholder
3382
+ */
3383
+ placeholder: String,
3384
+ /**
3385
+ * Use input text to search on options
3386
+ */
3387
+ searchable: Boolean,
3388
+ /**
3389
+ * Search function to filter options
3390
+ */
3391
+ searchFunction: {
3392
+ type: Function,
3393
+ default: void 0
3394
+ },
3395
+ /**
3396
+ * On searchable select is the input search placeholder
3397
+ */
3398
+ searchPlaceholder: {
3399
+ type: String,
3400
+ default: "Search..."
3401
+ },
3402
+ /**
3403
+ * The input search debounce time in ms
3404
+ */
3405
+ debounceSearch: {
3406
+ type: [Number, String],
3407
+ default: 0
3408
+ },
3409
+ /**
3410
+ * Manage modelValue as string[] or object[]
3411
+ */
3412
+ multiple: Boolean,
3413
+ /**
3414
+ * The min number of selected values
3415
+ */
3416
+ minValues: {
3417
+ type: [Number, String],
3418
+ default: 0
3419
+ },
3420
+ /**
3421
+ * The max number of selected values
3422
+ */
3423
+ maxValues: [Number, String],
3424
+ /**
3425
+ * If true the input will be unselectable
3426
+ * @deprecated use minValues instead
3427
+ */
3428
+ unselectable: { type: Boolean, default: true },
3429
+ /**
3430
+ * The select label separator visible to the user
3431
+ */
3432
+ separator: { type: String, default: ", " },
3433
+ /**
3434
+ * Show native select
3435
+ */
3436
+ native: Boolean,
3437
+ /**
3438
+ * Show badges
3439
+ */
3440
+ badges: Boolean,
3441
+ /**
3442
+ * Badge modifiers
3443
+ */
3444
+ badgeModifiers: {
3445
+ type: [String, Array],
3446
+ default: "action sm"
3447
+ },
3448
+ /**
3449
+ * Set dropdown width to the same as the trigger
3450
+ */
3451
+ triggerWidth: {
3452
+ ...DropdownProps.triggerWidth,
3453
+ default: true
3454
+ },
3455
+ /**
3456
+ * Dropdown modifiers
3457
+ */
3458
+ dropdownModifiers: {
3459
+ type: [String, Array],
3460
+ default: "mobile"
3461
+ },
3462
+ /**
3463
+ * Open dropdown on focus
3464
+ */
3465
+ autoOpen: {
3466
+ type: Boolean,
3467
+ default: false
3468
+ },
3469
+ /**
3470
+ * Select first option automatically
3471
+ */
3472
+ autoselectFirst: {
3473
+ type: Boolean,
3474
+ default: false
3475
+ },
3476
+ /**
3477
+ * Keep open dropdown on single select
3478
+ */
3479
+ keepOpen: {
3480
+ type: Boolean,
3481
+ default: false
3482
+ }
3483
+ };
3484
+ function useVvComboboxProps() {
3485
+ return {
3486
+ ...VvComboboxProps,
3487
+ options: {
3488
+ ...VvComboboxProps.options,
3489
+ type: Array
3490
+ },
3491
+ searchFunction: {
3492
+ ...VvComboboxProps.searchFunction,
3493
+ type: Function
3494
+ }
3495
+ };
3496
+ }
3322
3497
  const VvDropdownProps = {
3323
3498
  ...IdProps,
3324
3499
  ...DropdownProps,
@@ -4059,7 +4234,7 @@ const _hoisted_4$5 = { class: "vv-select__inner" };
4059
4234
  const _hoisted_5$4 = ["id"];
4060
4235
  const _hoisted_6$4 = ["disabled", "hidden"];
4061
4236
  const _hoisted_7$4 = ["disabled", "value"];
4062
- const _hoisted_8$3 = ["disabled", "label"];
4237
+ const _hoisted_8$4 = ["disabled", "label"];
4063
4238
  const _hoisted_9$2 = ["disabled", "value"];
4064
4239
  const _hoisted_10$1 = {
4065
4240
  key: 1,
@@ -4271,7 +4446,7 @@ const _sfc_main$e = /* @__PURE__ */ defineComponent({
4271
4446
  128
4272
4447
  /* KEYED_FRAGMENT */
4273
4448
  ))
4274
- ], 8, _hoisted_8$3))
4449
+ ], 8, _hoisted_8$4))
4275
4450
  ],
4276
4451
  64
4277
4452
  /* STABLE_FRAGMENT */
@@ -4334,185 +4509,10 @@ const _sfc_main$e = /* @__PURE__ */ defineComponent({
4334
4509
  ],
4335
4510
  2
4336
4511
  /* CLASS */
4337
- );
4338
- };
4339
- }
4340
- });
4341
- const VvComboboxProps = {
4342
- ...IdNameProps,
4343
- ...TabindexProps,
4344
- ...ValidProps,
4345
- ...InvalidProps,
4346
- ...HintProps,
4347
- ...LoadingProps,
4348
- ...DisabledProps,
4349
- ...ReadonlyProps,
4350
- ...ModifiersProps,
4351
- ...OptionsProps,
4352
- ...IconProps,
4353
- ...FloatingLabelProps,
4354
- ...DropdownProps,
4355
- ...LabelProps,
4356
- ...RequiredProps,
4357
- /**
4358
- * Dropdown show / hide transition name
4359
- */
4360
- transitionName: {
4361
- type: String,
4362
- default: "vv-dropdown--mobile-fade-block"
4363
- },
4364
- /**
4365
- * modelValue can be a string, number, boolean, object or array of string, number, boolean, object
4366
- */
4367
- modelValue: {
4368
- type: [String, Number, Boolean, Object, Array],
4369
- default: void 0
4370
- },
4371
- /**
4372
- * Label for no search results
4373
- */
4374
- noResultsLabel: { type: String, default: "No results" },
4375
- /**
4376
- * Label for no options available
4377
- */
4378
- noOptionsLabel: { type: String, default: "No options available" },
4379
- /**
4380
- * Label for selected option hint
4381
- */
4382
- selectedHintLabel: { type: String, default: "Selected" },
4383
- /**
4384
- * Label for deselect action button
4385
- */
4386
- deselectActionLabel: { type: String, default: "Deselect" },
4387
- /**
4388
- * Label for select option hint
4389
- */
4390
- selectHintLabel: { type: String, default: "Press enter to select" },
4391
- /**
4392
- * Label for deselected option hint
4393
- */
4394
- deselectHintLabel: { type: String, default: "Press enter to remove" },
4395
- /**
4396
- * Label close button
4397
- */
4398
- closeLabel: { type: String, default: "Close" },
4399
- /**
4400
- * Select input placeholder
4401
- */
4402
- placeholder: String,
4403
- /**
4404
- * Use input text to search on options
4405
- */
4406
- searchable: Boolean,
4407
- /**
4408
- * Search function to filter options
4409
- */
4410
- searchFunction: {
4411
- type: Function,
4412
- default: void 0
4413
- },
4414
- /**
4415
- * On searchable select is the input search placeholder
4416
- */
4417
- searchPlaceholder: {
4418
- type: String,
4419
- default: "Search..."
4420
- },
4421
- /**
4422
- * The input search debounce time in ms
4423
- */
4424
- debounceSearch: {
4425
- type: [Number, String],
4426
- default: 0
4427
- },
4428
- /**
4429
- * Manage modelValue as string[] or object[]
4430
- */
4431
- multiple: Boolean,
4432
- /**
4433
- * The min number of selected values
4434
- */
4435
- minValues: {
4436
- type: [Number, String],
4437
- default: 0
4438
- },
4439
- /**
4440
- * The max number of selected values
4441
- */
4442
- maxValues: [Number, String],
4443
- /**
4444
- * If true the input will be unselectable
4445
- * @deprecated use minValues instead
4446
- */
4447
- unselectable: { type: Boolean, default: true },
4448
- /**
4449
- * The select label separator visible to the user
4450
- */
4451
- separator: { type: String, default: ", " },
4452
- /**
4453
- * Show native select
4454
- */
4455
- native: Boolean,
4456
- /**
4457
- * Show badges
4458
- */
4459
- badges: Boolean,
4460
- /**
4461
- * Badge modifiers
4462
- */
4463
- badgeModifiers: {
4464
- type: [String, Array],
4465
- default: "action sm"
4466
- },
4467
- /**
4468
- * Set dropdown width to the same as the trigger
4469
- */
4470
- triggerWidth: {
4471
- ...DropdownProps.triggerWidth,
4472
- default: true
4473
- },
4474
- /**
4475
- * Dropdown modifiers
4476
- */
4477
- dropdownModifiers: {
4478
- type: [String, Array],
4479
- default: "mobile"
4480
- },
4481
- /**
4482
- * Open dropdown on focus
4483
- */
4484
- autoOpen: {
4485
- type: Boolean,
4486
- default: false
4487
- },
4488
- /**
4489
- * Select first option automatically
4490
- */
4491
- autoselectFirst: {
4492
- type: Boolean,
4493
- default: false
4494
- },
4495
- /**
4496
- * Keep open dropdown on single select
4497
- */
4498
- keepOpen: {
4499
- type: Boolean,
4500
- default: false
4501
- }
4502
- };
4503
- function useVvComboboxProps() {
4504
- return {
4505
- ...VvComboboxProps,
4506
- options: {
4507
- ...VvComboboxProps.options,
4508
- type: Array
4509
- },
4510
- searchFunction: {
4511
- ...VvComboboxProps.searchFunction,
4512
- type: Function
4513
- }
4514
- };
4515
- }
4512
+ );
4513
+ };
4514
+ }
4515
+ });
4516
4516
  const _hoisted_1$8 = ["id"];
4517
4517
  const _hoisted_2$6 = ["id", "for"];
4518
4518
  const _hoisted_3$4 = ["id", "aria-controls", "placeholder"];
@@ -4526,7 +4526,7 @@ const _hoisted_7$3 = {
4526
4526
  key: 0,
4527
4527
  class: "vv-select__value"
4528
4528
  };
4529
- const _hoisted_8$2 = ["aria-label", "onClick"];
4529
+ const _hoisted_8$3 = ["aria-label", "onClick"];
4530
4530
  const _hoisted_9$1 = {
4531
4531
  key: 1,
4532
4532
  class: "vv-select__input-after"
@@ -4948,7 +4948,7 @@ const _sfc_main$d = /* @__PURE__ */ defineComponent({
4948
4948
  onClick: withModifiers(($event) => onInput(option), ["stop"])
4949
4949
  }, [
4950
4950
  createVNode(_sfc_main$u, { name: "close" })
4951
- ], 8, _hoisted_8$2)) : createCommentVNode("v-if", true)
4951
+ ], 8, _hoisted_8$3)) : createCommentVNode("v-if", true)
4952
4952
  ]),
4953
4953
  _: 2
4954
4954
  /* DYNAMIC */
@@ -5588,7 +5588,7 @@ const _hoisted_4$2 = { class: "vv-input-file__wrapper" };
5588
5588
  const _hoisted_5$2 = ["id", "readonly", "disabled", "required", "placeholder", "aria-describedby", "aria-invalid", "aria-errormessage", "multiple", "accept", "capture", "name"];
5589
5589
  const _hoisted_6$2 = ["value"];
5590
5590
  const _hoisted_7$2 = ["onClick"];
5591
- const _hoisted_8$1 = ["title", "onClick"];
5591
+ const _hoisted_8$2 = ["title", "onClick"];
5592
5592
  const _hoisted_9 = { class: "vv-input-file__item-name" };
5593
5593
  const _hoisted_10 = { class: "vv-input-file__item-info" };
5594
5594
  const _hoisted_11 = ["title", "disabled", "onClick"];
@@ -5949,7 +5949,7 @@ const _sfc_main$a = /* @__PURE__ */ defineComponent({
5949
5949
  16
5950
5950
  /* FULL_PROPS */
5951
5951
  )
5952
- ], 8, _hoisted_8$1)) : createCommentVNode("v-if", true),
5952
+ ], 8, _hoisted_8$2)) : createCommentVNode("v-if", true),
5953
5953
  createElementVNode(
5954
5954
  "div",
5955
5955
  _hoisted_9,
@@ -6020,6 +6020,78 @@ const _sfc_main$a = /* @__PURE__ */ defineComponent({
6020
6020
  };
6021
6021
  }
6022
6022
  });
6023
+ function isDateIsoString(dateString) {
6024
+ if (typeof dateString !== "string") {
6025
+ return false;
6026
+ }
6027
+ if (!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?(?:Z|[+-]\d{2}:?\d{2})?$/.test(dateString)) {
6028
+ return false;
6029
+ }
6030
+ const d = new Date(dateString);
6031
+ return !Number.isNaN(d.getTime()) && d.toISOString() === dateString;
6032
+ }
6033
+ function getInputValueFromDate(date, typeOfInput = "date", withSeconds) {
6034
+ if (typeof date === "string") {
6035
+ if (!isDateIsoString(date)) {
6036
+ return "";
6037
+ }
6038
+ }
6039
+ const currentDate = new Date(date);
6040
+ if (Number.isNaN(currentDate.getTime())) {
6041
+ return "";
6042
+ }
6043
+ const span = (num) => num.toString().padStart(2, "0");
6044
+ let toReturn = `${currentDate.getFullYear()}-${span(currentDate.getMonth() + 1)}`;
6045
+ if (typeOfInput === "month") {
6046
+ return toReturn;
6047
+ }
6048
+ toReturn += `-${span(currentDate.getDate())}`;
6049
+ if (typeOfInput === "date") {
6050
+ return toReturn;
6051
+ }
6052
+ const time = withSeconds ? `${span(currentDate.getHours())}:${span(currentDate.getMinutes())}:${span(currentDate.getSeconds())}` : `${span(currentDate.getHours())}:${span(currentDate.getMinutes())}`;
6053
+ if (typeOfInput === "time") {
6054
+ return time;
6055
+ }
6056
+ return `${toReturn}T${time}`;
6057
+ }
6058
+ function getDateFromInputValue(value, typeOfInput = "date") {
6059
+ if (!(value == null ? void 0 : value.trim())) {
6060
+ return null;
6061
+ }
6062
+ const today = /* @__PURE__ */ new Date();
6063
+ const currentYear = today.getFullYear();
6064
+ const currentMonth = today.getMonth();
6065
+ const currentDate = today.getDate();
6066
+ if (typeOfInput === "date") {
6067
+ if (!/^\d{4}-\d{2}-\d{2}$/.test(value)) {
6068
+ throw new Error("Invalid date format. Expected: YYYY-MM-DD");
6069
+ }
6070
+ return /* @__PURE__ */ new Date(`${value}T00:00:00`);
6071
+ }
6072
+ if (typeOfInput === "month") {
6073
+ if (!/^\d{4}-\d{2}$/.test(value)) {
6074
+ throw new Error("Invalid month format. Expected: YYYY-MM");
6075
+ }
6076
+ return /* @__PURE__ */ new Date(`${value}-01T00:00:00`);
6077
+ }
6078
+ if (typeOfInput === "time") {
6079
+ if (!/^(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d)?$/.test(value)) {
6080
+ throw new Error("Invalid time format. Expected: HH:mm or HH:mm:ss");
6081
+ }
6082
+ if (value.length === 8) {
6083
+ return /* @__PURE__ */ new Date(`${currentYear}-${currentMonth + 1}-${currentDate}T${value}`);
6084
+ }
6085
+ return /* @__PURE__ */ new Date(`${currentYear}-${currentMonth + 1}-${currentDate}T${value}:00`);
6086
+ }
6087
+ if (!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2})?$/.test(value)) {
6088
+ throw new Error("Invalid datetime format. Expected: YYYY-MM-DDThh:mm or YYYY-MM-DDThh:mm:ss");
6089
+ }
6090
+ if (value.length === 16) {
6091
+ return /* @__PURE__ */ new Date(`${value}:00`);
6092
+ }
6093
+ return /* @__PURE__ */ new Date(`${value}`);
6094
+ }
6023
6095
  const INPUT_TYPES = {
6024
6096
  TEXT: "text",
6025
6097
  PASSWORD: "password",
@@ -6059,7 +6131,7 @@ const VvInputTextProps = {
6059
6131
  * Input value
6060
6132
  * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#value
6061
6133
  */
6062
- modelValue: [String, Number],
6134
+ modelValue: [String, Number, Date],
6063
6135
  /**
6064
6136
  * Type of form control
6065
6137
  * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#type
@@ -6533,7 +6605,7 @@ const _hoisted_6$1 = {
6533
6605
  class: "vv-input-text__limit"
6534
6606
  };
6535
6607
  const _hoisted_7$1 = { class: "flex-1" };
6536
- const _hoisted_8 = ["title", "onClick"];
6608
+ const _hoisted_8$1 = ["title", "onClick"];
6537
6609
  const __default__$8 = {
6538
6610
  name: "VvInputText"
6539
6611
  };
@@ -6579,8 +6651,17 @@ const _sfc_main$9 = /* @__PURE__ */ defineComponent({
6579
6651
  emit,
6580
6652
  (debounce == null ? void 0 : debounce.value) ?? 0
6581
6653
  );
6654
+ const hasSeconds = computed(() => {
6655
+ const stepValue = typeof step.value === "number" ? step.value : Number.parseInt(step.value);
6656
+ if (Number.isNaN(stepValue)) {
6657
+ return false;
6658
+ }
6659
+ return stepValue % 60 !== 0;
6660
+ });
6582
6661
  const NEGATIVE_ZERO_REGEX = /^-0?[.,]?[0*]?$/;
6583
6662
  const maskReady = ref(false);
6663
+ const modelValueDate = ref();
6664
+ const modelValueDateIsoString = ref();
6584
6665
  const { el, mask, typed, masked, unmasked } = useIMask(
6585
6666
  computed(
6586
6667
  () => {
@@ -6605,6 +6686,7 @@ const _sfc_main$9 = /* @__PURE__ */ defineComponent({
6605
6686
  {
6606
6687
  emit,
6607
6688
  onAccept: () => {
6689
+ var _a;
6608
6690
  if (!maskReady.value) {
6609
6691
  return;
6610
6692
  }
@@ -6628,42 +6710,51 @@ const _sfc_main$9 = /* @__PURE__ */ defineComponent({
6628
6710
  localModelValue.value = typed.value;
6629
6711
  return;
6630
6712
  }
6631
- if (type.value === INPUT_TYPES.DATE) {
6632
- if (el.value instanceof HTMLInputElement && el.value.type === "date") {
6633
- localModelValue.value = el.value.value;
6634
- return;
6635
- }
6636
- let date = typed.value;
6637
- if (date === null || date === "") {
6713
+ if (type.value === INPUT_TYPES.DATETIME_LOCAL || type.value === INPUT_TYPES.DATE || type.value === INPUT_TYPES.TIME || type.value === INPUT_TYPES.MONTH) {
6714
+ if (!typed.value) {
6638
6715
  if (!localModelValue.value) {
6639
6716
  return;
6640
6717
  }
6718
+ if (modelValueDate.value) {
6719
+ localModelValue.value = void 0;
6720
+ return;
6721
+ }
6641
6722
  localModelValue.value = "";
6642
6723
  return;
6643
6724
  }
6644
- if (!(date instanceof Date)) {
6645
- date = new Date(date);
6646
- }
6647
- localModelValue.value = `${date.getFullYear()}-${`0${date.getMonth() + 1}`.slice(-2)}-${`0${date.getDate()}`.slice(-2)}`;
6648
- return;
6649
- }
6650
- if (type.value === INPUT_TYPES.DATETIME_LOCAL) {
6651
- if (el.value instanceof HTMLInputElement && el.value.type === "datetime-local") {
6652
- localModelValue.value = el.value.value;
6725
+ if (!(typed.value instanceof Date) && !modelValueDate.value && !modelValueDateIsoString.value) {
6726
+ localModelValue.value = typed.value;
6653
6727
  return;
6654
6728
  }
6655
6729
  let date = typed.value;
6656
- if (date === null || date === "") {
6657
- if (!localModelValue.value) {
6730
+ if (!(date instanceof Date)) {
6731
+ date = getDateFromInputValue(typed.value, type.value);
6732
+ }
6733
+ if (modelValueDate.value || modelValueDateIsoString.value) {
6734
+ const toReturn = new Date(modelValueDate.value || modelValueDateIsoString.value);
6735
+ if (type.value === INPUT_TYPES.DATETIME_LOCAL || type.value === INPUT_TYPES.DATE || type.value === INPUT_TYPES.MONTH) {
6736
+ toReturn.setFullYear(date.getFullYear());
6737
+ toReturn.setMonth(date.getMonth());
6738
+ }
6739
+ if (type.value === INPUT_TYPES.DATETIME_LOCAL || type.value === INPUT_TYPES.DATE) {
6740
+ toReturn.setDate(date.getDate());
6741
+ }
6742
+ if (type.value === INPUT_TYPES.DATETIME_LOCAL || type.value === INPUT_TYPES.TIME) {
6743
+ toReturn.setHours(date.getHours());
6744
+ toReturn.setMinutes(date.getMinutes());
6745
+ toReturn.setSeconds(date.getSeconds());
6746
+ }
6747
+ if (modelValueDate.value instanceof Date) {
6748
+ if (((_a = localModelValue.value) == null ? void 0 : _a.getTime()) === toReturn.getTime()) {
6749
+ return;
6750
+ }
6751
+ localModelValue.value = toReturn;
6658
6752
  return;
6659
6753
  }
6660
- localModelValue.value = "";
6754
+ localModelValue.value = toReturn.toISOString();
6661
6755
  return;
6662
6756
  }
6663
- if (!(typed.value instanceof Date)) {
6664
- date = new Date(date);
6665
- }
6666
- localModelValue.value = `${date.getFullYear()}-${`0${date.getMonth() + 1}`.slice(-2)}-${`0${date.getDate()}`.slice(-2)}T${`0${date.getHours()}`.slice(-2)}:${`0${date.getMinutes()}`.slice(-2)}`;
6757
+ localModelValue.value = getInputValueFromDate(date, type.value, hasSeconds.value);
6667
6758
  return;
6668
6759
  }
6669
6760
  if (!localModelValue.value && !unmasked.value) {
@@ -6681,12 +6772,29 @@ const _sfc_main$9 = /* @__PURE__ */ defineComponent({
6681
6772
  return;
6682
6773
  }
6683
6774
  if (((_a = props.iMask) == null ? void 0 : _a.mask) === Date) {
6684
- typed.value = new Date(newValue);
6775
+ typed.value = newValue instanceof Date ? newValue : new Date(newValue);
6685
6776
  return;
6686
6777
  }
6687
6778
  if (type.value === INPUT_TYPES.NUMBER && NEGATIVE_ZERO_REGEX.test(unmasked.value) && newValue === 0) {
6688
6779
  return;
6689
6780
  }
6781
+ if (type.value === INPUT_TYPES.DATE || type.value === INPUT_TYPES.MONTH || type.value === INPUT_TYPES.DATETIME_LOCAL || type.value === INPUT_TYPES.TIME) {
6782
+ if (newValue instanceof Date || isDateIsoString(newValue)) {
6783
+ if (newValue instanceof Date) {
6784
+ modelValueDate.value = newValue;
6785
+ modelValueDateIsoString.value = void 0;
6786
+ } else {
6787
+ modelValueDateIsoString.value = newValue;
6788
+ modelValueDate.value = void 0;
6789
+ }
6790
+ const newDate = new Date(newValue);
6791
+ typed.value = getInputValueFromDate(newDate, type.value, hasSeconds.value);
6792
+ unmasked.value = typed.value;
6793
+ return;
6794
+ }
6795
+ modelValueDate.value = void 0;
6796
+ modelValueDateIsoString.value = void 0;
6797
+ }
6690
6798
  typed.value = newValue;
6691
6799
  unmasked.value = `${typed.value}`;
6692
6800
  }
@@ -6713,34 +6821,32 @@ const _sfc_main$9 = /* @__PURE__ */ defineComponent({
6713
6821
  const inputEl = el;
6714
6822
  const innerEl = ref();
6715
6823
  const wrapperEl = ref();
6716
- const dropdownEl = ref();
6824
+ const suggestionsDropdownEl = ref();
6717
6825
  __expose({ $inner: innerEl });
6718
6826
  const { focused } = useComponentFocus(inputEl, emit);
6719
6827
  const isFocused = computed(
6720
6828
  () => focused.value && !props.disabled && !props.readonly
6721
6829
  );
6722
6830
  watch(isFocused, (newValue) => {
6723
- var _a;
6831
+ var _a, _b;
6724
6832
  if (newValue && propsDefaults.value.selectOnFocus && inputEl.value) {
6725
6833
  inputEl.value.select();
6726
6834
  }
6727
- if (newValue) {
6728
- (_a = dropdownEl.value) == null ? void 0 : _a.show();
6835
+ if (newValue && ((_a = suggestions.value) == null ? void 0 : _a.size)) {
6836
+ (_b = suggestionsDropdownEl.value) == null ? void 0 : _b.show();
6729
6837
  return;
6730
6838
  }
6731
- setTimeout(() => {
6732
- if (isDirty.value && suggestions.value) {
6733
- const suggestionsLimit = props.maxSuggestions - 1;
6734
- if (suggestions.value.size > suggestionsLimit && !suggestions.value.has(localModelValue.value)) {
6735
- suggestions.value = new Set(
6736
- [...suggestions.value].slice(
6737
- suggestions.value.size - suggestionsLimit
6738
- )
6739
- );
6740
- }
6741
- suggestions.value.add(localModelValue.value);
6839
+ if (isDirty.value && suggestions.value) {
6840
+ const suggestionsLimit = props.maxSuggestions;
6841
+ if (suggestions.value.size >= suggestionsLimit && !suggestions.value.has(localModelValue.value)) {
6842
+ suggestions.value = new Set(
6843
+ [...suggestions.value].slice(
6844
+ suggestions.value.size - suggestionsLimit + 1
6845
+ )
6846
+ );
6742
6847
  }
6743
- }, 300);
6848
+ suggestions.value.add(localModelValue.value);
6849
+ }
6744
6850
  });
6745
6851
  const isVisible = useElementVisibility(inputEl);
6746
6852
  watch(isVisible, (newValue) => {
@@ -6838,7 +6944,7 @@ const _sfc_main$9 = /* @__PURE__ */ defineComponent({
6838
6944
  function onSuggestionSelect(suggestion) {
6839
6945
  var _a;
6840
6946
  localModelValue.value = suggestion;
6841
- (_a = dropdownEl.value) == null ? void 0 : _a.hide();
6947
+ (_a = suggestionsDropdownEl.value) == null ? void 0 : _a.hide();
6842
6948
  }
6843
6949
  function onSuggestionRemove(suggestion) {
6844
6950
  var _a;
@@ -7100,8 +7206,8 @@ const _sfc_main$9 = /* @__PURE__ */ defineComponent({
7100
7206
  ]), 1032, ["id"]),
7101
7207
  unref(hasSuggestions) ? (openBlock(), createBlock(_sfc_main$i, {
7102
7208
  key: 1,
7103
- ref_key: "dropdownEl",
7104
- ref: dropdownEl,
7209
+ ref_key: "suggestionsDropdownEl",
7210
+ ref: suggestionsDropdownEl,
7105
7211
  reference: unref(wrapperEl),
7106
7212
  "autofocus-first": false,
7107
7213
  "trigger-width": true
@@ -7140,7 +7246,7 @@ const _sfc_main$9 = /* @__PURE__ */ defineComponent({
7140
7246
  16
7141
7247
  /* FULL_PROPS */
7142
7248
  )
7143
- ], 8, _hoisted_8)) : createCommentVNode("v-if", true)
7249
+ ], 8, _hoisted_8$1)) : createCommentVNode("v-if", true)
7144
7250
  ]),
7145
7251
  _: 2
7146
7252
  /* DYNAMIC */
@@ -7773,6 +7879,7 @@ const SPELLCHECK = {
7773
7879
  const VvTextareaEvents = ["update:modelValue", "focus", "blur", "keyup"];
7774
7880
  const VvTextareaProps = {
7775
7881
  ...InputTextareaProps,
7882
+ ...StorageProps,
7776
7883
  /**
7777
7884
  * Textarea value
7778
7885
  * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea#value
@@ -7798,27 +7905,57 @@ const VvTextareaProps = {
7798
7905
  * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea#wrap
7799
7906
  */
7800
7907
  spellcheck: { type: [Boolean, String], default: SPELLCHECK.default },
7908
+ /**
7909
+ * VvIcon name for remove suggestion button
7910
+ * @see VVIcon
7911
+ */
7912
+ iconRemoveSuggestion: {
7913
+ type: [String, Object],
7914
+ default: ACTION_ICONS.remove
7915
+ },
7916
+ /**
7917
+ * Label for remove suggestion button
7918
+ */
7919
+ labelRemoveSuggestion: {
7920
+ type: String,
7921
+ default: "Remove suggestion"
7922
+ },
7923
+ /**
7924
+ * Maximum number of suggestions
7925
+ */
7926
+ maxSuggestions: {
7927
+ type: Number,
7928
+ default: 5
7929
+ },
7930
+ /**
7931
+ * Select input text on focus
7932
+ */
7933
+ selectOnFocus: {
7934
+ type: Boolean,
7935
+ default: false
7936
+ },
7801
7937
  /**
7802
7938
  * If true, the textarea will be resizable
7803
7939
  */
7804
7940
  resizable: Boolean
7805
7941
  };
7806
7942
  const _hoisted_1 = ["for"];
7807
- const _hoisted_2 = { class: "vv-textarea__wrapper" };
7808
- const _hoisted_3 = {
7943
+ const _hoisted_2 = {
7809
7944
  key: 0,
7810
7945
  class: "vv-textarea__input-before"
7811
7946
  };
7812
- const _hoisted_4 = { class: "vv-textarea__inner" };
7813
- const _hoisted_5 = ["id"];
7814
- const _hoisted_6 = {
7947
+ const _hoisted_3 = { class: "vv-textarea__inner" };
7948
+ const _hoisted_4 = ["id"];
7949
+ const _hoisted_5 = {
7815
7950
  key: 1,
7816
7951
  class: "vv-textarea__input-after"
7817
7952
  };
7818
- const _hoisted_7 = {
7953
+ const _hoisted_6 = {
7819
7954
  key: 2,
7820
7955
  class: "vv-textarea__limit"
7821
7956
  };
7957
+ const _hoisted_7 = { class: "flex-1" };
7958
+ const _hoisted_8 = ["title", "onClick"];
7822
7959
  const __default__$1 = {
7823
7960
  name: "VvTextarea"
7824
7961
  };
@@ -7835,11 +7972,15 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
7835
7972
  VvTextareaProps,
7836
7973
  props
7837
7974
  );
7838
- const textarea = ref();
7975
+ const textareaEl = ref();
7976
+ const wrapperEl = ref();
7977
+ const suggestionsDropdownEl = ref();
7839
7978
  const {
7840
7979
  id,
7841
7980
  icon,
7842
7981
  iconPosition,
7982
+ iconRemoveSuggestion,
7983
+ labelRemoveSuggestion,
7843
7984
  label,
7844
7985
  modelValue,
7845
7986
  count,
@@ -7849,7 +7990,9 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
7849
7990
  modifiers,
7850
7991
  debounce,
7851
7992
  minlength,
7852
- maxlength
7993
+ maxlength,
7994
+ storageKey,
7995
+ storageType
7853
7996
  } = toRefs(props);
7854
7997
  const hasId = useUniqueId(id);
7855
7998
  const hasHintId = computed(() => `${hasId.value}-hint`);
@@ -7858,8 +8001,33 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
7858
8001
  );
7859
8002
  const localModelValue = useDebouncedInput(modelValue, emit, debounce == null ? void 0 : debounce.value);
7860
8003
  const { hasIconBefore, hasIconAfter } = useComponentIcon(icon, iconPosition);
7861
- const { focused } = useComponentFocus(textarea, emit);
7862
- const isVisible = useElementVisibility(textarea);
8004
+ const { hasIcon: hasIconRemoveSuggestion } = useComponentIcon(iconRemoveSuggestion);
8005
+ const { focused } = useComponentFocus(textareaEl, emit);
8006
+ const isFocused = computed(
8007
+ () => focused.value && !props.disabled && !props.readonly
8008
+ );
8009
+ watch(isFocused, (newValue) => {
8010
+ var _a, _b;
8011
+ if (newValue && propsDefaults.value.selectOnFocus && textareaEl.value) {
8012
+ textareaEl.value.select();
8013
+ }
8014
+ if (newValue && ((_a = suggestions.value) == null ? void 0 : _a.size)) {
8015
+ (_b = suggestionsDropdownEl.value) == null ? void 0 : _b.show();
8016
+ return;
8017
+ }
8018
+ if (isDirty.value && suggestions.value) {
8019
+ const suggestionsLimit = props.maxSuggestions;
8020
+ if (suggestions.value.size >= suggestionsLimit && !suggestions.value.has(localModelValue.value)) {
8021
+ suggestions.value = new Set(
8022
+ [...suggestions.value].slice(
8023
+ suggestions.value.size - suggestionsLimit + 1
8024
+ )
8025
+ );
8026
+ }
8027
+ suggestions.value.add(localModelValue.value);
8028
+ }
8029
+ });
8030
+ const isVisible = useElementVisibility(textareaEl);
7863
8031
  watch(isVisible, (newValue) => {
7864
8032
  if (newValue && props.autofocus) {
7865
8033
  focused.value = true;
@@ -7884,6 +8052,31 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
7884
8052
  }
7885
8053
  return void 0;
7886
8054
  });
8055
+ const suggestions = usePersistence(
8056
+ storageKey,
8057
+ storageType,
8058
+ /* @__PURE__ */ new Set()
8059
+ );
8060
+ const filteredSuggestions = computed(() => {
8061
+ if (!suggestions.value) {
8062
+ return [];
8063
+ }
8064
+ return [...suggestions.value].filter(
8065
+ (suggestion) => isEmpty(localModelValue.value) || `${suggestion}`.toLowerCase().includes(`${localModelValue.value}`.toLowerCase()) && suggestion !== localModelValue.value
8066
+ ).reverse();
8067
+ });
8068
+ const hasSuggestions = computed(
8069
+ () => (storageKey == null ? void 0 : storageKey.value) && suggestions.value && suggestions.value.size > 0
8070
+ );
8071
+ function onSuggestionSelect(suggestion) {
8072
+ var _a;
8073
+ localModelValue.value = suggestion;
8074
+ (_a = suggestionsDropdownEl.value) == null ? void 0 : _a.hide();
8075
+ }
8076
+ function onSuggestionRemove(suggestion) {
8077
+ var _a;
8078
+ (_a = suggestions.value) == null ? void 0 : _a.delete(suggestion);
8079
+ }
7887
8080
  const {
7888
8081
  HintSlot,
7889
8082
  hasHintLabelOrSlot,
@@ -7952,49 +8145,59 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
7952
8145
  for: unref(hasId),
7953
8146
  class: "vv-textarea__label"
7954
8147
  }, toDisplayString(unref(label)), 9, _hoisted_1)) : createCommentVNode("v-if", true),
7955
- createElementVNode("div", _hoisted_2, [
7956
- _ctx.$slots.before ? (openBlock(), createElementBlock("div", _hoisted_3, [
7957
- renderSlot(_ctx.$slots, "before", normalizeProps(guardReactiveProps(unref(slotProps))))
7958
- ])) : createCommentVNode("v-if", true),
7959
- createElementVNode("div", _hoisted_4, [
7960
- unref(hasIconBefore) ? (openBlock(), createBlock(
7961
- _sfc_main$u,
7962
- mergeProps({ key: 0 }, unref(hasIconBefore), { class: "vv-textarea__icon" }),
7963
- null,
7964
- 16
7965
- /* FULL_PROPS */
7966
- )) : createCommentVNode("v-if", true),
7967
- withDirectives(createElementVNode("textarea", mergeProps({
7968
- id: unref(hasId),
7969
- ref_key: "textarea",
7970
- ref: textarea,
7971
- "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => isRef(localModelValue) ? localModelValue.value = $event : null)
7972
- }, unref(hasAttrs), {
7973
- onKeyup: _cache[1] || (_cache[1] = ($event) => emit("keyup", $event))
7974
- }), null, 16, _hoisted_5), [
7975
- [vModelText, unref(localModelValue)]
8148
+ createElementVNode(
8149
+ "div",
8150
+ {
8151
+ ref_key: "wrapperEl",
8152
+ ref: wrapperEl,
8153
+ class: "vv-textarea__wrapper"
8154
+ },
8155
+ [
8156
+ _ctx.$slots.before ? (openBlock(), createElementBlock("div", _hoisted_2, [
8157
+ renderSlot(_ctx.$slots, "before", normalizeProps(guardReactiveProps(unref(slotProps))))
8158
+ ])) : createCommentVNode("v-if", true),
8159
+ createElementVNode("div", _hoisted_3, [
8160
+ unref(hasIconBefore) ? (openBlock(), createBlock(
8161
+ _sfc_main$u,
8162
+ mergeProps({ key: 0 }, unref(hasIconBefore), { class: "vv-textarea__icon" }),
8163
+ null,
8164
+ 16
8165
+ /* FULL_PROPS */
8166
+ )) : createCommentVNode("v-if", true),
8167
+ withDirectives(createElementVNode("textarea", mergeProps({
8168
+ id: unref(hasId),
8169
+ ref_key: "textareaEl",
8170
+ ref: textareaEl,
8171
+ "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => isRef(localModelValue) ? localModelValue.value = $event : null)
8172
+ }, unref(hasAttrs), {
8173
+ onKeyup: _cache[1] || (_cache[1] = ($event) => emit("keyup", $event))
8174
+ }), null, 16, _hoisted_4), [
8175
+ [vModelText, unref(localModelValue)]
8176
+ ]),
8177
+ unref(hasIconAfter) ? (openBlock(), createBlock(
8178
+ _sfc_main$u,
8179
+ mergeProps({ key: 1 }, unref(hasIconAfter), { class: "vv-textarea__icon vv-textarea__icon-after" }),
8180
+ null,
8181
+ 16
8182
+ /* FULL_PROPS */
8183
+ )) : createCommentVNode("v-if", true)
7976
8184
  ]),
7977
- unref(hasIconAfter) ? (openBlock(), createBlock(
7978
- _sfc_main$u,
7979
- mergeProps({ key: 1 }, unref(hasIconAfter), { class: "vv-textarea__icon vv-textarea__icon-after" }),
7980
- null,
7981
- 16
7982
- /* FULL_PROPS */
7983
- )) : createCommentVNode("v-if", true)
7984
- ]),
7985
- _ctx.$slots.after ? (openBlock(), createElementBlock("div", _hoisted_6, [
7986
- renderSlot(_ctx.$slots, "after", normalizeProps(guardReactiveProps(unref(slotProps))))
7987
- ])) : createCommentVNode("v-if", true),
7988
- unref(count) ? (openBlock(), createElementBlock("span", _hoisted_7, [
7989
- renderSlot(_ctx.$slots, "count", normalizeProps(guardReactiveProps(unref(slotProps))), () => [
7990
- createTextVNode(
7991
- toDisplayString(unref(countFormatted)),
7992
- 1
7993
- /* TEXT */
7994
- )
7995
- ])
7996
- ])) : createCommentVNode("v-if", true)
7997
- ]),
8185
+ _ctx.$slots.after ? (openBlock(), createElementBlock("div", _hoisted_5, [
8186
+ renderSlot(_ctx.$slots, "after", normalizeProps(guardReactiveProps(unref(slotProps))))
8187
+ ])) : createCommentVNode("v-if", true),
8188
+ unref(count) ? (openBlock(), createElementBlock("span", _hoisted_6, [
8189
+ renderSlot(_ctx.$slots, "count", normalizeProps(guardReactiveProps(unref(slotProps))), () => [
8190
+ createTextVNode(
8191
+ toDisplayString(unref(countFormatted)),
8192
+ 1
8193
+ /* TEXT */
8194
+ )
8195
+ ])
8196
+ ])) : createCommentVNode("v-if", true)
8197
+ ],
8198
+ 512
8199
+ /* NEED_PATCH */
8200
+ ),
7998
8201
  createVNode(unref(HintSlot), {
7999
8202
  id: unref(hasHintId),
8000
8203
  class: "vv-textarea__hint"
@@ -8030,7 +8233,62 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
8030
8233
  ]),
8031
8234
  key: "3"
8032
8235
  } : void 0
8033
- ]), 1032, ["id"])
8236
+ ]), 1032, ["id"]),
8237
+ unref(hasSuggestions) ? (openBlock(), createBlock(_sfc_main$i, {
8238
+ key: 1,
8239
+ ref_key: "suggestionsDropdownEl",
8240
+ ref: suggestionsDropdownEl,
8241
+ reference: unref(wrapperEl),
8242
+ "autofocus-first": false,
8243
+ "trigger-width": true
8244
+ }, {
8245
+ items: withCtx(() => [
8246
+ (openBlock(true), createElementBlock(
8247
+ Fragment,
8248
+ null,
8249
+ renderList(unref(filteredSuggestions), (value) => {
8250
+ return openBlock(), createBlock(_sfc_main$f, {
8251
+ key: value,
8252
+ onClick: withModifiers(($event) => onSuggestionSelect(value), ["stop"])
8253
+ }, {
8254
+ default: withCtx(() => [
8255
+ createElementVNode("div", _hoisted_7, [
8256
+ renderSlot(_ctx.$slots, "suggestion", mergeProps({ ref_for: true }, { value }), () => [
8257
+ createTextVNode(
8258
+ toDisplayString(value),
8259
+ 1
8260
+ /* TEXT */
8261
+ )
8262
+ ])
8263
+ ]),
8264
+ unref(suggestions) && unref(hasIconRemoveSuggestion) ? (openBlock(), createElementBlock("button", {
8265
+ key: 0,
8266
+ type: "button",
8267
+ tabindex: "-1",
8268
+ class: "cursor-pointer",
8269
+ title: unref(labelRemoveSuggestion),
8270
+ onClick: withModifiers(($event) => onSuggestionRemove(value), ["stop"])
8271
+ }, [
8272
+ createVNode(
8273
+ _sfc_main$u,
8274
+ mergeProps({ ref_for: true }, unref(hasIconRemoveSuggestion)),
8275
+ null,
8276
+ 16
8277
+ /* FULL_PROPS */
8278
+ )
8279
+ ], 8, _hoisted_8)) : createCommentVNode("v-if", true)
8280
+ ]),
8281
+ _: 2
8282
+ /* DYNAMIC */
8283
+ }, 1032, ["onClick"]);
8284
+ }),
8285
+ 128
8286
+ /* KEYED_FRAGMENT */
8287
+ ))
8288
+ ]),
8289
+ _: 3
8290
+ /* FORWARDED */
8291
+ }, 8, ["reference"])) : createCommentVNode("v-if", true)
8034
8292
  ],
8035
8293
  2
8036
8294
  /* CLASS */