@1337exp/taoui 1.11.6 → 1.13.0

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.
package/README.md CHANGED
@@ -40,12 +40,12 @@ change a handful of CSS variables and the whole kit follows.
40
40
  - **TaoSwitch** — boolean toggle (`role="switch"`)
41
41
  - **TaoRadio** / **TaoRadioGroup** — classic radios: longer labels, can stack vertically
42
42
  - **TaoSegmented** / **TaoSegmentedOption** — compact exclusive choice among 2–5 short options. Not tabs
43
- - **TaoSelect** — dropdown with keyboard, same chrome as Input. Clear via “Clear” in the list or Delete
44
- - **TaoCombobox** — Select with a field: type to filter, `allow-create` writes a custom value into `v-model`, `create` lets the parent append the list
43
+ - **TaoSelect** — dropdown with keyboard, same chrome as Input. `size` (`small` / `medium` / `large`, same scale as Button). Clear via “Clear” in the list or Delete; `clearable="false"` turns clearing off, `#clear` replaces the row content
44
+ - **TaoCombobox** — Select with a field: type to filter, `allow-create` writes a custom value into `v-model`, `create` lets the parent append the list. Takes the same `size`, `clearable` and `#clear` as `TaoSelect`
45
45
  - **TaoDate** — a single day: `YYYY-MM-DD`, no time, no timezone. Calendar popup like Select
46
46
  - **TaoDateRange** — a period: `v-model` is `{ start, end }` or `null`. First click is start, second is end (they swap if end is earlier). An incomplete pick is not written to the model
47
47
  - **TaoFormField** — shared label / hint / error for form controls
48
- - **TaoInputNumber** — number with min/max/step and ± on the right. Empty value is `null`
48
+ - **TaoInputNumber** — number with min/max/step and ± on the right. Empty value is `null`. `@commit` fires once when an edit is finished (blur, Enter, ±, arrow), unlike `v-model`, which updates on every keystroke
49
49
  - **TaoQuantity** — cart quantity: `− | field | +`, integers, stock; minus at the minimum can remove the row
50
50
  - **TaoTextarea** — autosizing multiline. `maxlength` caps input, `count` shows “entered / max”
51
51
  - **TaoPinCode** — N cells. By default a click clears the cell and everything to the right (`clear-on="focus"`); `clear-on="input"` replaces the digit only when typing. The last cell blurs and emits `complete`
@@ -269,6 +269,16 @@ confirm.defaults({ ok: 'Yes', cancel: 'No' })
269
269
 
270
270
  `TaoSelect` opens from the keyboard (arrows, Enter, Esc); the list flips at the viewport edge. Delete or “Clear” at the bottom of the list resets the value to `null`.
271
271
 
272
+ When `null` is not a valid value (a grid step, a sort order), pass `:clearable="false"`: the clear row and the Delete / Backspace shortcut disappear. The clear row label is `clear-text`; for an icon or any markup use the `#clear` slot. `size` is `small` / `medium` (default) / `large` and also scales the open list.
273
+
274
+ ```vue
275
+ <TaoSelect v-model="step" :options="steps" size="small" :clearable="false" />
276
+
277
+ <TaoSelect v-model="city" :options="cities">
278
+ <template #clear><TaoIcon name="close" /> Reset</template>
279
+ </TaoSelect>
280
+ ```
281
+
272
282
  `TaoCombobox` is the same menu with a field. Typing filters options. `allow-create` writes the typed string into `v-model` when there is no exact match. The list does not mutate itself: listen to `create` and append an option from the parent.
273
283
 
274
284
  `TaoFormField` also wraps `TaoTextarea`, `TaoCheckbox`, `TaoSwitch`, `TaoRadioGroup`, and `TaoSegmented` — id, hint, and error are forwarded for you.
@@ -481,6 +491,7 @@ document.documentElement.setAttribute('data-tao-theme', 'light')
481
491
  - `--tao-radius-control`, `--tao-radius-panel` — radii (small controls vs large panels)
482
492
  - `--tao-shadow-panel`, `--tao-shadow-overlay` — shadows
483
493
  - `--tao-font-size-*` — type scale in `primitives.css`: `xs`–`xl` controls, `2xl`–`4xl` titles / prose
494
+ - `--tao-control-height-small` / `-medium` / `-large` — one height scale (26 / 36 / 44px) for every control with `size`: Button, Segmented, Select, Combobox. `--tao-field-height` (= medium) is the height of fields without `size`: Input, InputNumber, Date, DateRange, Quantity
484
495
 
485
496
  The full list lives in `src/styles/semantic.css` — the only file worth opening
486
497
  to see the whole theming API.
package/README.ru.md CHANGED
@@ -40,12 +40,12 @@
40
40
  - **TaoSwitch** — переключатель для булевых настроек (`role="switch"`)
41
41
  - **TaoRadio** / **TaoRadioGroup** — классические радиокнопки: длинные подписи, можно столбиком
42
42
  - **TaoSegmented** / **TaoSegmentedOption** — компактный выбор из 2–5 коротких вариантов. Не вкладки
43
- - **TaoSelect** — выпадающий список с клавиатурой, тот же визуал, что у Input. Сброс — «Очистить» в списке или Delete
44
- - **TaoCombobox** — Select с полем: фильтр по вводу, `allow-create` пишет своё в `v-model`, `create` — чтобы родитель дополнил список
43
+ - **TaoSelect** — выпадающий список с клавиатурой, тот же визуал, что у Input. `size` (`small` / `medium` / `large`, та же шкала, что у Button). Сброс — «Очистить» в списке или Delete; `clearable="false"` отключает сброс, слот `#clear` заменяет содержимое строки
44
+ - **TaoCombobox** — Select с полем: фильтр по вводу, `allow-create` пишет своё в `v-model`, `create` — чтобы родитель дополнил список. Те же `size`, `clearable` и `#clear`, что у `TaoSelect`
45
45
  - **TaoDate** — один день: `YYYY-MM-DD`, без часов и пояса. Календарь как у Select
46
46
  - **TaoDateRange** — период: `v-model` — `{ start, end }` или `null`. Первый клик — начало, второй — конец (если конец раньше — меняются местами). Неполный выбор в модель не пишется
47
47
  - **TaoFormField** — общие label / hint / error для полей формы
48
- - **TaoInputNumber** — число с min/max/step и кнопками ± справа. Пустое значение — `null`
48
+ - **TaoInputNumber** — число с min/max/step и кнопками ± справа. Пустое значение — `null`. `@commit` срабатывает один раз, когда правка закончена (blur, Enter, ±, стрелка), в отличие от `v-model`, который обновляется на каждую клавишу
49
49
  - **TaoQuantity** — количество в корзине: `− | поле | +`, целые штуки, сток, минус на минимуме может убрать строку
50
50
  - **TaoTextarea** — многострочное поле с авто-высотой. `maxlength` ограничивает ввод, `count` показывает «введено / максимум»
51
51
  - **TaoPinCode** — пин-код из N полей. По умолчанию клик стирает ячейку и все справа (`clear-on="focus"`); `clear-on="input"` заменяет цифру только при вводе. Последняя ячейка снимает фокус и эмитит `complete`
@@ -270,6 +270,16 @@ confirm.defaults({ ok: 'Yes', cancel: 'No' })
270
270
 
271
271
  `TaoSelect` открывается с клавиатуры (стрелки, Enter, Esc), список переворачивается у края экрана. Delete или «Очистить» внизу списка сбрасывает значение в `null`.
272
272
 
273
+ Если `null` не допустим (шаг сетки, порядок сортировки), передайте `:clearable="false"`: строка сброса и Delete / Backspace пропадут. Подпись строки сброса — `clear-text`, для иконки или своей разметки есть слот `#clear`. `size` — `small` / `medium` (по умолчанию) / `large`, масштабирует и раскрытый список.
274
+
275
+ ```vue
276
+ <TaoSelect v-model="step" :options="steps" size="small" :clearable="false" />
277
+
278
+ <TaoSelect v-model="city" :options="cities">
279
+ <template #clear><TaoIcon name="close" /> Сбросить</template>
280
+ </TaoSelect>
281
+ ```
282
+
273
283
  `TaoCombobox` — то же меню, но с полем. Печатаете — варианты режутся. `allow-create` пишет введённое в `v-model`, если точного совпадения нет. Список сам не меняется: слушайте `create` и добавьте option снаружи.
274
284
 
275
285
  `TaoFormField` также оборачивает `TaoTextarea`, `TaoCheckbox`, `TaoSwitch`, `TaoRadioGroup` и `TaoSegmented` — id, hint и error прокидываются сами.
@@ -484,6 +494,7 @@ document.documentElement.setAttribute('data-tao-theme', 'light')
484
494
  - `--tao-radius-control`, `--tao-radius-panel` — скругления (мелкие контролы vs крупные панели)
485
495
  - `--tao-shadow-panel`, `--tao-shadow-overlay` — тени
486
496
  - `--tao-font-size-*` — шкала кегля в `primitives.css`: `xs`–`xl` контролы, `2xl`–`4xl` заголовки / проза
497
+ - `--tao-control-height-small` / `-medium` / `-large` — единая шкала высот (26 / 36 / 44px) для всех контролов с `size`: Button, Segmented, Select, Combobox. `--tao-field-height` (= medium) — высота полей без `size`: Input, InputNumber, Date, DateRange, Quantity
487
498
 
488
499
  Полный список — в `src/styles/semantic.css`, он же единственный файл,
489
500
  который стоит открыть, чтобы понять весь доступный API темизации.
package/dist/index.cjs CHANGED
@@ -67,7 +67,7 @@
67
67
  }
68
68
  return target;
69
69
  };
70
- const TaoButton = /* @__PURE__ */ _export_sfc(_sfc_main$Z, [["__scopeId", "data-v-1e1847ba"]]);
70
+ const TaoButton = /* @__PURE__ */ _export_sfc(_sfc_main$Z, [["__scopeId", "data-v-8966c285"]]);
71
71
  const _sfc_main$Y = /* @__PURE__ */ vue.defineComponent({
72
72
  ...{ name: "TaoBlock" },
73
73
  __name: "TaoBlock",
@@ -193,7 +193,7 @@
193
193
  };
194
194
  }
195
195
  });
196
- const TaoInput = /* @__PURE__ */ _export_sfc(_sfc_main$X, [["__scopeId", "data-v-8e122e7e"]]);
196
+ const TaoInput = /* @__PURE__ */ _export_sfc(_sfc_main$X, [["__scopeId", "data-v-e0d2a454"]]);
197
197
  const _hoisted_1$N = {
198
198
  key: 0,
199
199
  class: "tao-input-group__addon tao-input-group__addon--before"
@@ -263,7 +263,7 @@
263
263
  incrementLabel: { default: "Увеличить" },
264
264
  decrementLabel: { default: "Уменьшить" }
265
265
  },
266
- emits: ["update:modelValue", "blur", "focus"],
266
+ emits: ["update:modelValue", "commit", "blur", "focus"],
267
267
  setup(__props, { emit: __emit }) {
268
268
  const props = __props;
269
269
  const emit = __emit;
@@ -331,9 +331,8 @@
331
331
  function commit(value) {
332
332
  const next = value === null ? null : clamp(value);
333
333
  emit("update:modelValue", next);
334
- if (!focused.value) {
335
- draft.value = toDraft(next);
336
- }
334
+ draft.value = toDraft(next);
335
+ emit("commit", next);
337
336
  }
338
337
  function bump(direction) {
339
338
  if (props.disabled) {
@@ -364,6 +363,11 @@
364
363
  emit("blur", event);
365
364
  }
366
365
  function onKeydown(event) {
366
+ if (event.key === "Enter") {
367
+ const parsed = parseDraft(draft.value);
368
+ commit(parsed === "incomplete" ? null : parsed);
369
+ return;
370
+ }
367
371
  if (event.key === "ArrowUp") {
368
372
  event.preventDefault();
369
373
  bump(1);
@@ -434,7 +438,7 @@
434
438
  };
435
439
  }
436
440
  });
437
- const TaoInputNumber = /* @__PURE__ */ _export_sfc(_sfc_main$V, [["__scopeId", "data-v-f2141b0c"]]);
441
+ const TaoInputNumber = /* @__PURE__ */ _export_sfc(_sfc_main$V, [["__scopeId", "data-v-4614f4ff"]]);
438
442
  const _hoisted_1$L = ["aria-label", "disabled"];
439
443
  const _hoisted_2$E = { "aria-hidden": "true" };
440
444
  const _hoisted_3$x = ["id", "value", "disabled", "aria-invalid", "aria-describedby", "aria-valuenow", "aria-valuemin", "aria-valuemax"];
@@ -620,7 +624,7 @@
620
624
  };
621
625
  }
622
626
  });
623
- const TaoQuantity = /* @__PURE__ */ _export_sfc(_sfc_main$U, [["__scopeId", "data-v-821124cf"]]);
627
+ const TaoQuantity = /* @__PURE__ */ _export_sfc(_sfc_main$U, [["__scopeId", "data-v-17b4aada"]]);
624
628
  const _hoisted_1$K = {
625
629
  key: 0,
626
630
  class: "tao-card__cover"
@@ -3941,7 +3945,9 @@
3941
3945
  placeholder: { default: "Выберите" },
3942
3946
  disabled: { type: Boolean, default: false },
3943
3947
  error: { type: Boolean, default: false },
3944
- clearText: { default: "Очистить" }
3948
+ clearText: { default: "Очистить" },
3949
+ clearable: { type: Boolean, default: true },
3950
+ size: { default: "medium" }
3945
3951
  },
3946
3952
  emits: ["update:modelValue", "change"],
3947
3953
  setup(__props, { emit: __emit }) {
@@ -4045,7 +4051,7 @@
4045
4051
  if (props.disabled) {
4046
4052
  return;
4047
4053
  }
4048
- if ((event.key === "Backspace" || event.key === "Delete") && selected.value) {
4054
+ if ((event.key === "Backspace" || event.key === "Delete") && selected.value && props.clearable) {
4049
4055
  event.preventDefault();
4050
4056
  clear();
4051
4057
  return;
@@ -4086,7 +4092,7 @@
4086
4092
  return;
4087
4093
  }
4088
4094
  if (event.key === "Backspace" || event.key === "Delete") {
4089
- if (selected.value) {
4095
+ if (selected.value && props.clearable) {
4090
4096
  event.preventDefault();
4091
4097
  clear();
4092
4098
  }
@@ -4132,7 +4138,7 @@
4132
4138
  return (_ctx, _cache) => {
4133
4139
  var _a;
4134
4140
  return vue.openBlock(), vue.createElementBlock("div", {
4135
- class: vue.normalizeClass(["tao-select", { "tao-select--open": open.value, "tao-select--invalid": invalid.value }])
4141
+ class: vue.normalizeClass(["tao-select", [`tao-select--${__props.size}`, { "tao-select--open": open.value, "tao-select--invalid": invalid.value }]])
4136
4142
  }, [
4137
4143
  vue.createElementVNode("button", {
4138
4144
  id: controlId.value,
@@ -4163,7 +4169,7 @@
4163
4169
  key: 0,
4164
4170
  ref_key: "panelRef",
4165
4171
  ref: panelRef,
4166
- class: "tao-select__panel",
4172
+ class: vue.normalizeClass(["tao-select__panel", `tao-select__panel--${__props.size}`]),
4167
4173
  style: vue.normalizeStyle(listStyle.value)
4168
4174
  }, [
4169
4175
  vue.createElementVNode("ul", {
@@ -4196,7 +4202,7 @@
4196
4202
  }, vue.toDisplayString(option.label), 43, _hoisted_4$h);
4197
4203
  }), 128))
4198
4204
  ], 40, _hoisted_3$i),
4199
- selected.value ? (vue.openBlock(), vue.createElementBlock("button", {
4205
+ __props.clearable && selected.value ? (vue.openBlock(), vue.createElementBlock("button", {
4200
4206
  key: 0,
4201
4207
  type: "button",
4202
4208
  class: "tao-select__clear",
@@ -4208,13 +4214,13 @@
4208
4214
  vue.createTextVNode(vue.toDisplayString(__props.clearText), 1)
4209
4215
  ], true)
4210
4216
  ], 32)) : vue.createCommentVNode("", true)
4211
- ], 4)) : vue.createCommentVNode("", true)
4217
+ ], 6)) : vue.createCommentVNode("", true)
4212
4218
  ]))
4213
4219
  ], 2);
4214
4220
  };
4215
4221
  }
4216
4222
  });
4217
- const TaoSelect = /* @__PURE__ */ _export_sfc(_sfc_main$o, [["__scopeId", "data-v-854360a4"]]);
4223
+ const TaoSelect = /* @__PURE__ */ _export_sfc(_sfc_main$o, [["__scopeId", "data-v-e067dbde"]]);
4218
4224
  const _hoisted_1$n = ["id", "aria-expanded", "aria-activedescendant", "aria-invalid", "aria-describedby", "disabled", "placeholder", "value"];
4219
4225
  const _hoisted_2$l = {
4220
4226
  key: 0,
@@ -4232,6 +4238,8 @@
4232
4238
  error: { type: Boolean, default: false },
4233
4239
  emptyText: { default: "Ничего не найдено" },
4234
4240
  clearText: { default: "Очистить" },
4241
+ clearable: { type: Boolean, default: true },
4242
+ size: { default: "medium" },
4235
4243
  allowCreate: { type: Boolean, default: false }
4236
4244
  },
4237
4245
  emits: ["update:modelValue", "change", "create"],
@@ -4605,11 +4613,14 @@
4605
4613
  });
4606
4614
  return (_ctx, _cache) => {
4607
4615
  return vue.openBlock(), vue.createElementBlock("div", {
4608
- class: vue.normalizeClass(["tao-combobox", {
4609
- "tao-combobox--open": open.value,
4610
- "tao-combobox--invalid": invalid.value,
4611
- "tao-combobox--disabled": __props.disabled
4612
- }])
4616
+ class: vue.normalizeClass(["tao-combobox", [
4617
+ `tao-combobox--${__props.size}`,
4618
+ {
4619
+ "tao-combobox--open": open.value,
4620
+ "tao-combobox--invalid": invalid.value,
4621
+ "tao-combobox--disabled": __props.disabled
4622
+ }
4623
+ ]])
4613
4624
  }, [
4614
4625
  vue.createElementVNode("div", {
4615
4626
  ref_key: "fieldRef",
@@ -4655,7 +4666,7 @@
4655
4666
  key: 0,
4656
4667
  ref_key: "panelRef",
4657
4668
  ref: panelRef,
4658
- class: "tao-combobox__panel",
4669
+ class: vue.normalizeClass(["tao-combobox__panel", `tao-combobox__panel--${__props.size}`]),
4659
4670
  style: vue.normalizeStyle(listStyle.value)
4660
4671
  }, [
4661
4672
  vue.createElementVNode("ul", {
@@ -4698,7 +4709,7 @@
4698
4709
  ], 42, _hoisted_3$h);
4699
4710
  }), 128))
4700
4711
  ], 512),
4701
- selected.value ? (vue.openBlock(), vue.createElementBlock("button", {
4712
+ __props.clearable && selected.value ? (vue.openBlock(), vue.createElementBlock("button", {
4702
4713
  key: 0,
4703
4714
  type: "button",
4704
4715
  class: "tao-combobox__clear",
@@ -4709,13 +4720,13 @@
4709
4720
  vue.createTextVNode(vue.toDisplayString(__props.clearText), 1)
4710
4721
  ], true)
4711
4722
  ], 32)) : vue.createCommentVNode("", true)
4712
- ], 4)) : vue.createCommentVNode("", true)
4723
+ ], 6)) : vue.createCommentVNode("", true)
4713
4724
  ]))
4714
4725
  ], 2);
4715
4726
  };
4716
4727
  }
4717
4728
  });
4718
- const TaoCombobox = /* @__PURE__ */ _export_sfc(_sfc_main$n, [["__scopeId", "data-v-c1f14f5a"]]);
4729
+ const TaoCombobox = /* @__PURE__ */ _export_sfc(_sfc_main$n, [["__scopeId", "data-v-1254c942"]]);
4719
4730
  const ISO_DATE = /^(\d{4})-(\d{2})-(\d{2})$/;
4720
4731
  function formatTaoDateIso(parts) {
4721
4732
  return `${String(parts.y).padStart(4, "0")}-${String(parts.m).padStart(2, "0")}-${String(parts.d).padStart(2, "0")}`;
@@ -5264,7 +5275,7 @@
5264
5275
  };
5265
5276
  }
5266
5277
  });
5267
- const TaoDate = /* @__PURE__ */ _export_sfc(_sfc_main$m, [["__scopeId", "data-v-a996d893"]]);
5278
+ const TaoDate = /* @__PURE__ */ _export_sfc(_sfc_main$m, [["__scopeId", "data-v-64d8f6aa"]]);
5268
5279
  const _hoisted_1$l = ["id", "aria-expanded", "aria-invalid", "aria-describedby", "disabled"];
5269
5280
  const _hoisted_2$j = { class: "tao-date-range__value" };
5270
5281
  const _hoisted_3$f = {
@@ -5730,7 +5741,7 @@
5730
5741
  };
5731
5742
  }
5732
5743
  });
5733
- const TaoDateRange = /* @__PURE__ */ _export_sfc(_sfc_main$l, [["__scopeId", "data-v-45e07f55"]]);
5744
+ const TaoDateRange = /* @__PURE__ */ _export_sfc(_sfc_main$l, [["__scopeId", "data-v-70505320"]]);
5734
5745
  const _hoisted_1$k = ["for"];
5735
5746
  const _hoisted_2$i = ["id", "checked", "disabled", "aria-checked", "aria-invalid", "aria-describedby"];
5736
5747
  const _hoisted_3$e = {
@@ -6175,7 +6186,7 @@
6175
6186
  };
6176
6187
  }
6177
6188
  });
6178
- const TaoSegmentedOption = /* @__PURE__ */ _export_sfc(_sfc_main$g, [["__scopeId", "data-v-f55dc6a0"]]);
6189
+ const TaoSegmentedOption = /* @__PURE__ */ _export_sfc(_sfc_main$g, [["__scopeId", "data-v-a47bc5c9"]]);
6179
6190
  const _hoisted_1$f = ["role", "aria-live"];
6180
6191
  const _hoisted_2$d = { class: "tao-alert__body" };
6181
6192
  const _hoisted_3$b = {