@kashi-ui/elements 0.25.0 → 1.0.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.
Files changed (70) hide show
  1. package/README.md +11 -1
  2. package/dist/appointment.d.ts +40 -0
  3. package/dist/appointment.js +175 -0
  4. package/dist/base.d.ts +408 -0
  5. package/dist/base.js +31 -0
  6. package/dist/basic.d.ts +43 -0
  7. package/dist/basic.js +222 -0
  8. package/dist/calendar.js +21 -20
  9. package/dist/cdn/appointment-CrIZi8Bp.js +1 -0
  10. package/dist/cdn/base-DTQ50VdG.js +1 -0
  11. package/dist/cdn/basic-CrEW2RKF.js +1 -0
  12. package/dist/cdn/calendar-CYRrdGIf.js +16 -0
  13. package/dist/cdn/charts-D6KM26Vp.js +1 -0
  14. package/dist/cdn/combobox-6EFI2qqN.js +1 -0
  15. package/dist/cdn/controls-BwebEIlf.js +1 -0
  16. package/dist/cdn/display-DFuMkcj5.js +1 -0
  17. package/dist/cdn/fields-DhLIhHQ8.js +1 -0
  18. package/dist/cdn/forms-BHivKDdC.js +1 -0
  19. package/dist/cdn/holidays-DgbIAdlt.js +1 -0
  20. package/dist/cdn/inputs-R7nEHfbV.js +1 -0
  21. package/dist/cdn/kashi-elements.js +1 -1
  22. package/dist/cdn/map-H3xiZd8Y.js +12 -0
  23. package/dist/cdn/{menu-DhrqyLgy.js → menu-BAUSubXk.js} +1 -1
  24. package/dist/cdn/nav-NK-v48B5.js +1 -0
  25. package/dist/cdn/overlay-CBv8grz3.js +1 -0
  26. package/dist/cdn/pickers-BHzNt_X8.js +1 -0
  27. package/dist/cdn/table-Bt9WVLoo.js +1 -0
  28. package/dist/cdn/text-D4a_hlwL.js +1 -0
  29. package/dist/cdn/time-DJ3p1wvd.js +1 -0
  30. package/dist/cdn/words-BdADG_9U.js +1 -0
  31. package/dist/cdn.d.ts +1 -0
  32. package/dist/cdn.js +4 -0
  33. package/dist/charts.js +27 -24
  34. package/dist/combobox.d.ts +6 -5
  35. package/dist/combobox.js +29 -20
  36. package/dist/controls.js +15 -15
  37. package/dist/display.js +17 -14
  38. package/dist/fields.js +3 -3
  39. package/dist/forms.d.ts +3 -3
  40. package/dist/forms.js +54 -47
  41. package/dist/index.d.ts +12 -2
  42. package/dist/index.js +7 -1
  43. package/dist/inputs.d.ts +3 -3
  44. package/dist/inputs.js +31 -30
  45. package/dist/map.js +16 -13
  46. package/dist/nav.js +18 -16
  47. package/dist/overlay.js +5 -5
  48. package/dist/pickers.d.ts +1 -1
  49. package/dist/pickers.js +39 -38
  50. package/dist/table.js +7 -7
  51. package/dist/toast.js +3 -3
  52. package/package.json +4 -4
  53. package/dist/cdn/base-Cmq7zeIG.js +0 -1
  54. package/dist/cdn/calendar-Dm3fq2bs.js +0 -16
  55. package/dist/cdn/charts-DNOWi4sJ.js +0 -1
  56. package/dist/cdn/combobox-ZGrZ5okg.js +0 -1
  57. package/dist/cdn/controls-K-OZcjg4.js +0 -1
  58. package/dist/cdn/digits-DE1YGT94.js +0 -1
  59. package/dist/cdn/display-C975tS7j.js +0 -1
  60. package/dist/cdn/fields-BUTaSN8m.js +0 -1
  61. package/dist/cdn/forms-C-effPKn.js +0 -1
  62. package/dist/cdn/inputs-BjOddAM7.js +0 -1
  63. package/dist/cdn/jalali-BiM5Kfep.js +0 -1
  64. package/dist/cdn/map-BHuusa4t.js +0 -12
  65. package/dist/cdn/nav-D_w5BV_K.js +0 -1
  66. package/dist/cdn/overlay-DX9un2xm.js +0 -1
  67. package/dist/cdn/pickers-BFLpUruK.js +0 -1
  68. package/dist/cdn/table-DPQfDMs-.js +0 -1
  69. package/dist/cdn/text-D1U32D6K.js +0 -1
  70. package/dist/cdn/words-9OdzG7y6.js +0 -1
package/dist/display.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { formatJalali, formatMoney, formatRelative, fromISODate, numberToWords, rialToToman, toFaDigits, tomanToRial } from "@kashi-ui/persian";
2
- import { HTMLBase, define, emit, esc } from "./base.js";
2
+ import { define, digitsOf, emit, esc, HTMLBase, lang, msg } from "./base.js";
3
3
  /** «2026-03-21» به نیمه‌شب محلی، و بقیهٔ قالب‌ها (با ساعت) با Date */
4
4
  const parseDateTime = (text) => {
5
5
  if (!text)
@@ -24,19 +24,21 @@ export class KashiMoney extends Display {
24
24
  const unit = this.getAttribute("unit") === "rial" ? "rial" : "toman";
25
25
  const from = this.getAttribute("from") === "rial" ? "rial" : this.getAttribute("from") === "toman" ? "toman" : unit;
26
26
  const compact = this.hasAttribute("compact");
27
- const digits = this.getAttribute("digits") === "latin" ? "latin" : "fa";
27
+ const digits = digitsOf(this);
28
28
  const signed = this.hasAttribute("signed");
29
29
  const size = this.getAttribute("size") ?? "md";
30
30
  const n = from === unit ? value : from === "rial" ? rialToToman(value) : tomanToRial(value);
31
- const amount = formatMoney(n, { unit, compact, digits, showUnit: false });
32
- const full = formatMoney(n, { unit, compact });
33
- const unitText = full.endsWith("همت") ? null : unit === "toman" ? "تومان" : "ریال";
31
+ const locale = lang(), M = msg();
32
+ const amount = formatMoney(n, { unit, compact, digits, locale, showUnit: false });
33
+ const full = formatMoney(n, { unit, compact, locale });
34
+ const unitName = unit === "toman" ? M.money.toman : M.money.rial;
35
+ const unitText = full.endsWith("همت") ? null : unitName;
34
36
  const spoken = this.getAttribute("words") !== "false" && Number.isSafeInteger(Math.round(n))
35
- ? `${numberToWords(Math.round(n))} ${unit === "toman" ? "تومان" : "ریال"}`
37
+ ? `${numberToWords(Math.round(n), { locale })} ${unitName}`
36
38
  : null;
37
39
  const tone = signed ? (n > 0 ? "positive" : n < 0 ? "negative" : null) : null;
38
40
  const hide = spoken ? ' aria-hidden="true"' : "";
39
- this.innerHTML = `<data value="${n}" class="k-money k-money--${esc(size)}"${tone ? ` data-tone="${tone}"` : ""}${spoken ? ` title="${esc(spoken)}"` : ""}><span class="k-money__amount"${hide}>${signed && n > 0 ? "+" : ""}${esc(amount)}</span>${unitText ? `<span class="k-money__unit"${hide}>${unitText}</span>` : ""}${spoken ? `<span class="k-sr-only">${n < 0 ? "" : signed && n > 0 ? "مثبت " : ""}${esc(spoken)}</span>` : ""}</data>`;
41
+ this.innerHTML = `<data value="${n}" class="k-money k-money--${esc(size)}"${tone ? ` data-tone="${tone}"` : ""}${spoken ? ` title="${esc(spoken)}"` : ""}><span class="k-money__amount"${hide}>${signed && n > 0 ? "+" : ""}${esc(amount)}</span>${unitText ? `<span class="k-money__unit"${hide}>${unitText}</span>` : ""}${spoken ? `<span class="k-sr-only">${n < 0 ? "" : signed && n > 0 ? M.money.positive : ""}${esc(spoken)}</span>` : ""}</data>`;
40
42
  }
41
43
  }
42
44
  KashiMoney.observedAttributes = ["value", "unit", "from", "compact", "digits", "signed", "words", "size"];
@@ -50,8 +52,8 @@ export class KashiDate extends Display {
50
52
  }
51
53
  const f = this.getAttribute("format");
52
54
  const style = f === "numeric" || f === "full" ? f : "long";
53
- const digits = this.getAttribute("digits") === "latin" ? "latin" : "fa";
54
- this.innerHTML = `<time datetime="${esc(this.getAttribute("datetime"))}">${esc(formatJalali(d, { style, digits }))}</time>`;
55
+ const digits = digitsOf(this);
56
+ this.innerHTML = `<time datetime="${esc(this.getAttribute("datetime"))}">${esc(formatJalali(d, { style, digits, locale: lang() }))}</time>`;
55
57
  }
56
58
  }
57
59
  KashiDate.observedAttributes = ["datetime", "format", "digits"];
@@ -71,8 +73,8 @@ export class KashiRelativeTime extends Display {
71
73
  this.textContent = "";
72
74
  return;
73
75
  }
74
- const digits = this.getAttribute("digits") === "latin" ? "latin" : "fa";
75
- this.innerHTML = `<time datetime="${d.toISOString()}" title="${esc(formatJalali(d, { style: "full", digits }))}">${esc(formatRelative(d, { digits }))}</time>`;
76
+ const digits = digitsOf(this);
77
+ this.innerHTML = `<time datetime="${d.toISOString()}" title="${esc(formatJalali(d, { style: "full", digits, locale: lang() }))}">${esc(formatRelative(d, { digits, locale: lang() }))}</time>`;
76
78
  }
77
79
  }
78
80
  KashiRelativeTime.observedAttributes = ["datetime", "digits", "refresh"];
@@ -114,14 +116,15 @@ export class KashiCountdown extends HTMLBase {
114
116
  render() {
115
117
  const left = this.remaining;
116
118
  const d = Math.floor(left / 86400), h = Math.floor((left % 86400) / 3600), m = Math.floor((left % 3600) / 60), s = left % 60;
117
- const fa = this.getAttribute("digits") !== "latin";
119
+ const fa = digitsOf(this) === "fa";
118
120
  const f = (x) => (fa ? toFaDigits(String(x)) : String(x));
119
- const spoken = [d && `${f(d)} روز`, h && `${f(h)} ساعت`, m && `${f(m)} دقیقه`, `${f(s)} ثانیه`].filter(Boolean).join(" و ");
121
+ const C = msg().countdown;
122
+ const spoken = [d && `${f(d)} ${C.days}`, h && `${f(h)} ${C.hours}`, m && `${f(m)} ${C.minutes}`, `${f(s)} ${C.seconds}`].filter(Boolean).join(msg().common.and);
120
123
  const label = this.getAttribute("label");
121
124
  const aria = esc(label ? `${label}: ${spoken}` : spoken);
122
125
  const doneAttr = left === 0 ? ' data-done=""' : "";
123
126
  if (this.getAttribute("variant") === "blocks") {
124
- const units = [...(d ? [[d, "روز"]] : []), [h, "ساعت"], [m, "دقیقه"], [s, "ثانیه"]];
127
+ const units = [...(d ? [[d, C.days]] : []), [h, C.hours], [m, C.minutes], [s, C.seconds]];
125
128
  this.innerHTML = `<div role="timer" aria-label="${aria}" class="k-countdown k-countdown--blocks"${doneAttr}>${units.map(([v, name]) => `<span class="k-countdown__unit" aria-hidden="true"><span class="k-countdown__num">${f(pad(v))}</span><span class="k-countdown__name">${name}</span></span>`).join("")}</div>`;
126
129
  }
127
130
  else {
package/dist/fields.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { onlyDigits, toFaDigits } from "@kashi-ui/persian";
2
- import { HTMLBase, define, emit, esc, fieldHTML, setMessages, syncHidden, uid } from "./base.js";
2
+ import { define, digitsOf, emit, esc, fieldHTML, HTMLBase, msg, setMessages, syncHidden, uid } from "./base.js";
3
3
  /**
4
4
  * کد تأیید یک‌بارمصرف: یک input واقعی (نه شش input جدا)، پس چسباندن، پاک کردن،
5
5
  * صفحه‌خوان و پر شدن خودکار کد پیامکی (autocomplete="one-time-code") کار می‌کنند.
@@ -49,7 +49,7 @@ export class KashiOtp extends HTMLBase {
49
49
  const length = this.length;
50
50
  const group = Number(this.getAttribute("group-after")) || 0;
51
51
  const ariaLabel = this.getAttribute("aria-label");
52
- const label = this.hasAttribute("label") ? this.getAttribute("label") : ariaLabel ? null : "کد تأیید";
52
+ const label = this.hasAttribute("label") ? this.getAttribute("label") : ariaLabel ? null : msg().otp.label;
53
53
  const slots = Array.from({ length }, (_, i) => `${group && i === group ? '<span class="k-otp__sep" aria-hidden="true"></span>' : ""}<span class="k-otp__slot" aria-hidden="true"></span>`).join("");
54
54
  const control = `<div class="k-otp${this.getAttribute("size") === "sm" ? " k-otp--sm" : ""}"><input id="${id}" class="k-otp__input" type="text" inputmode="numeric" autocomplete="one-time-code" pattern="\\d*" maxlength="${length * 2}"${this.hasAttribute("disabled") ? " disabled" : ""}${!label && ariaLabel ? ` aria-label="${esc(ariaLabel)}"` : ""}>${slots}</div>`;
55
55
  this.querySelector(":scope > .k-field")?.remove();
@@ -88,7 +88,7 @@ export class KashiOtp extends HTMLBase {
88
88
  }
89
89
  /** فقط خانه‌ها؛ مقدار input را دست نمی‌زند تا تایپ کاربر پیش از رویداد input پاک نشود */
90
90
  paintSlots() {
91
- const fa = this.getAttribute("digits") !== "latin";
91
+ const fa = digitsOf(this) === "fa";
92
92
  const focused = this.ownerDocument.activeElement === this.input;
93
93
  const active = Math.min(this.caret, this.length - 1);
94
94
  this.querySelectorAll(".k-otp__slot").forEach((slot, i) => {
package/dist/forms.d.ts CHANGED
@@ -93,7 +93,7 @@ declare abstract class TextField extends HTMLBase {
93
93
  protected valueSet: boolean;
94
94
  protected text: string;
95
95
  protected abstract multiline: boolean;
96
- protected abstract defaultLabel: string;
96
+ protected abstract get defaultLabel(): string;
97
97
  protected abstract hint(): string | null;
98
98
  connectedCallback(): void;
99
99
  attributeChangedCallback(name: string, old: string | null, next: string | null): void;
@@ -109,7 +109,7 @@ declare abstract class TextField extends HTMLBase {
109
109
  export declare class KashiPersianTextarea extends TextField {
110
110
  static observedAttributes: string[];
111
111
  protected multiline: boolean;
112
- protected defaultLabel: string;
112
+ protected get defaultLabel(): string;
113
113
  protected render(): void;
114
114
  private result;
115
115
  protected hint(): string | null;
@@ -118,7 +118,7 @@ export declare class KashiPersianTextarea extends TextField {
118
118
  export declare class KashiKeyboardFix extends TextField {
119
119
  static observedAttributes: string[];
120
120
  protected multiline: boolean;
121
- protected defaultLabel: string;
121
+ protected get defaultLabel(): string;
122
122
  protected render(): void;
123
123
  protected hint(): string | null;
124
124
  }
package/dist/forms.js CHANGED
@@ -1,5 +1,5 @@
1
- import { PLATE_LETTERS, fixKeyboardLayout, fixPersianText, formatNumber, formatPlate, formatTime, isValidPlate, looksLikeWrongLayout, onlyDigits, parseTime, plateType, toFaDigits, } from "@kashi-ui/persian";
2
- import { HTMLBase, afterParse, bool, define, emit, esc, fieldHTML, setMessages, syncHidden, uid } from "./base.js";
1
+ import { PLATE_LETTERS, fixKeyboardLayout, fixPersianText, formatNumber, formatPlate, formatTime, isValidPlate, looksLikeWrongLayout, onlyDigits, parseTime, plateType, toFaDigits } from "@kashi-ui/persian";
2
+ import { afterParse, bool, define, digitsOf, emit, esc, fieldHTML, HTMLBase, lang, localeDigits, msg, num, setMessages, syncHidden, uid } from "./base.js";
3
3
  import { searchText } from "./combobox.js";
4
4
  const CHECK = '<svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m5 10.5 3.2 3L15 7"/></svg>';
5
5
  const X = '<svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="m6 6 8 8M14 6l-8 8"/></svg>';
@@ -80,7 +80,7 @@ export class KashiMultiSelect extends HTMLBase {
80
80
  render() {
81
81
  const id = this.key;
82
82
  const ariaLabel = this.getAttribute("aria-label");
83
- const label = this.hasAttribute("label") ? this.getAttribute("label") : ariaLabel ? null : "انتخاب";
83
+ const label = this.hasAttribute("label") ? this.getAttribute("label") : ariaLabel ? null : msg().multiSelect.label;
84
84
  const off = this.hasAttribute("disabled");
85
85
  const control = `<div class="k-combobox k-multiselect"><div class="k-tag-input"><input id="${id}" class="k-tag-input__control" role="combobox" aria-autocomplete="list" aria-expanded="false" aria-controls="${id}-list" autocomplete="off"${off ? " disabled" : ""}${!label && ariaLabel ? ` aria-label="${esc(ariaLabel)}"` : ""}></div><ul id="${id}-list" role="listbox" aria-multiselectable="true" class="k-listbox" hidden style="inset-block-start: calc(100% + 6px)"${label ? ` aria-label="${esc(label)}"` : ""}></ul><span id="${id}-count" class="k-sr-only"></span><span class="k-sr-only" aria-live="polite"></span></div>`;
86
86
  this.querySelector(":scope > .k-field")?.remove();
@@ -91,9 +91,9 @@ export class KashiMultiSelect extends HTMLBase {
91
91
  this.box.addEventListener("click", (e) => {
92
92
  const rm = e.target.closest("[data-remove]");
93
93
  if (rm)
94
- this.set(this.chosen.filter((v) => v !== rm.dataset.remove), `${this.labelOf(rm.dataset.remove)} حذف شد`);
94
+ this.set(this.chosen.filter((v) => v !== rm.dataset.remove), msg().common.removed(this.labelOf(rm.dataset.remove)));
95
95
  else if (e.target.closest("[data-clear]"))
96
- this.set([], "همه حذف شد");
96
+ this.set([], msg().multiSelect.clearedAll);
97
97
  this.input.focus();
98
98
  });
99
99
  this.input.addEventListener("input", () => {
@@ -127,10 +127,10 @@ export class KashiMultiSelect extends HTMLBase {
127
127
  return;
128
128
  const on = this.chosen.includes(o.value);
129
129
  if (!on && this.full)
130
- return this.announce(`حداکثر ${toFaDigits(Number(this.getAttribute("max")))} مورد`);
130
+ return this.announce(msg().common.max(num(this, Number(this.getAttribute("max")))));
131
131
  this.query = "";
132
132
  this.input.value = "";
133
- this.set(on ? this.chosen.filter((v) => v !== o.value) : [...this.chosen, o.value], `${o.label} ${on ? "حذف شد" : "انتخاب شد"}`);
133
+ this.set(on ? this.chosen.filter((v) => v !== o.value) : [...this.chosen, o.value], on ? msg().common.removed(o.label) : msg().common.selected(o.label));
134
134
  }
135
135
  set(next, message) {
136
136
  this.chosen = next;
@@ -186,18 +186,18 @@ export class KashiMultiSelect extends HTMLBase {
186
186
  }
187
187
  else if (e.key === "Backspace" && !this.input.value && this.chosen.length) {
188
188
  const last = this.chosen.at(-1);
189
- this.set(this.chosen.slice(0, -1), `${this.labelOf(last)} حذف شد`);
189
+ this.set(this.chosen.slice(0, -1), msg().common.removed(this.labelOf(last)));
190
190
  }
191
191
  }
192
192
  paint() {
193
193
  const off = this.hasAttribute("disabled");
194
194
  this.box.querySelectorAll(".k-badge, [data-clear]").forEach((el) => el.remove());
195
- const badges = this.chosen.map((v) => `<span class="k-badge k-badge--brand${off ? "" : " k-badge--removable"}">${esc(this.labelOf(v))}${off ? "" : `<button type="button" class="k-badge__remove" data-remove="${esc(v)}" aria-label="حذف ${esc(this.labelOf(v))}">${X}</button>`}</span>`).join("");
195
+ const badges = this.chosen.map((v) => `<span class="k-badge k-badge--brand${off ? "" : " k-badge--removable"}">${esc(this.labelOf(v))}${off ? "" : `<button type="button" class="k-badge__remove" data-remove="${esc(v)}" aria-label="${esc(msg().common.remove(this.labelOf(v)))}">${X}</button>`}</span>`).join("");
196
196
  this.input.insertAdjacentHTML("beforebegin", badges);
197
197
  if (this.chosen.length > 1 && !off)
198
- this.box.insertAdjacentHTML("beforeend", `<button type="button" class="k-input__action" data-clear aria-label="پاک کردن همه">${X}</button>`);
198
+ this.box.insertAdjacentHTML("beforeend", `<button type="button" class="k-input__action" data-clear aria-label="${esc(msg().common.clearAll)}">${X}</button>`);
199
199
  this.input.placeholder = this.chosen.length ? "" : (this.getAttribute("placeholder") ?? "");
200
- this.querySelector(`#${this.key}-count`).textContent = `${toFaDigits(this.chosen.length)} مورد انتخاب شده`;
200
+ this.querySelector(`#${this.key}-count`).textContent = msg().multiSelect.selected(num(this, this.chosen.length));
201
201
  const error = this.getAttribute("error");
202
202
  this.box.toggleAttribute("data-invalid", !!error);
203
203
  setMessages(this.querySelector(":scope > .k-field"), this.input, this.key, error, this.getAttribute("hint"), `${this.key}-count`);
@@ -218,7 +218,7 @@ export class KashiMultiSelect extends HTMLBase {
218
218
  const on = this.chosen.includes(o.value);
219
219
  return `<li id="${this.key}-list-${i}" data-i="${i}" role="option" aria-selected="${on}"${o.disabled || (!on && full) ? ' aria-disabled="true"' : ""}${i === this.active ? " data-active" : ""} class="k-option k-option--check"><span class="k-multiselect__box" aria-hidden="true">${on ? CHECK : ""}</span><span class="k-option__body"><span>${mark(o.label)}</span>${o.description ? `<span class="k-option__desc">${esc(o.description)}</span>` : ""}</span></li>`;
220
220
  }).join("")
221
- : '<li class="k-listbox__empty" role="presentation">نتیجه‌ای پیدا نشد.</li>';
221
+ : `<li class="k-listbox__empty" role="presentation">${esc(msg().common.noResults)}</li>`;
222
222
  const act = this.active >= 0 ? this.listbox.querySelector(`[data-i="${this.active}"]`) : null;
223
223
  if (act) {
224
224
  this.input.setAttribute("aria-activedescendant", act.id);
@@ -283,7 +283,7 @@ export class KashiSlider extends HTMLBase {
283
283
  }
284
284
  fmt(n) {
285
285
  const unit = this.getAttribute("unit");
286
- return `${formatNumber(n)}${unit ? ` ${unit}` : ""}`;
286
+ return `${formatNumber(n, { digits: digitsOf(this) })}${unit ? ` ${unit}` : ""}`;
287
287
  }
288
288
  render() {
289
289
  const label = this.getAttribute("label");
@@ -294,11 +294,11 @@ export class KashiSlider extends HTMLBase {
294
294
  const input = (which) => {
295
295
  const v = which === "lo" ? this.lo : this.hi;
296
296
  const n = name ? (range ? `${name}_${which === "lo" ? "min" : "max"}` : name) : "";
297
- return `<input type="range" class="k-slider__input" data-which="${which}" min="${this.min}" max="${this.max}" step="${this.num("step", 1)}" value="${v}"${off ? " disabled" : ""}${n ? ` name="${esc(n)}"` : ""}${range ? ` aria-label="${which === "lo" ? "حداقل" : "حداکثر"}${label ? ` ${esc(label)}` : ""}"` : label ? ` aria-labelledby="${this.key}-label"` : ""} aria-valuetext="${esc(this.fmt(v))}">`;
297
+ return `<input type="range" class="k-slider__input" data-which="${which}" min="${this.min}" max="${this.max}" step="${this.num("step", 1)}" value="${v}"${off ? " disabled" : ""}${n ? ` name="${esc(n)}"` : ""}${range ? ` aria-label="${esc(which === "lo" ? msg().slider.from : msg().slider.to)}${label ? ` ${esc(label)}` : ""}"` : label ? ` aria-labelledby="${this.key}-label"` : ""} aria-valuetext="${esc(this.fmt(v))}">`;
298
298
  };
299
299
  const marks = (this.getAttribute("marks") ?? "").split(/[,،]/).map((s) => s.trim()).filter(Boolean).map(Number);
300
300
  const showValue = this.getAttribute("show-value") !== "false";
301
- this.innerHTML = `<div class="k-slider"${range ? ' data-range=""' : ""}>${label || showValue ? `<div class="k-slider__head">${label ? `<span class="k-label" id="${this.key}-label">${esc(label)}</span>` : ""}${showValue ? `<span class="k-slider__value" aria-hidden="true">${esc(range ? `${this.fmt(this.lo)} تا ${this.fmt(this.hi)}` : this.fmt(this.hi))}</span>` : ""}</div>` : ""}<div class="k-slider__track" style="--_from: ${range ? pct(this.lo) : "0%"}; --_to: ${pct(this.hi)}"><span class="k-slider__fill" aria-hidden="true"></span>${range ? input("lo") : ""}${input("hi")}</div>${marks.length ? `<div class="k-slider__marks" aria-hidden="true">${marks.map((m) => `<span>${esc(this.fmt(m))}</span>`).join("")}</div>` : ""}</div>`;
301
+ this.innerHTML = `<div class="k-slider"${range ? ' data-range=""' : ""}>${label || showValue ? `<div class="k-slider__head">${label ? `<span class="k-label" id="${this.key}-label">${esc(label)}</span>` : ""}${showValue ? `<span class="k-slider__value" aria-hidden="true">${esc(range ? `${this.fmt(this.lo)}${msg().common.range}${this.fmt(this.hi)}` : this.fmt(this.hi))}</span>` : ""}</div>` : ""}<div class="k-slider__track" style="--_from: ${range ? pct(this.lo) : "0%"}; --_to: ${pct(this.hi)}"><span class="k-slider__fill" aria-hidden="true"></span>${range ? input("lo") : ""}${input("hi")}</div>${marks.length ? `<div class="k-slider__marks" aria-hidden="true">${marks.map((m) => `<span>${esc(this.fmt(m))}</span>`).join("")}</div>` : ""}</div>`;
302
302
  this.rendered = true;
303
303
  this.querySelectorAll(".k-slider__input").forEach((el) => el.addEventListener("input", () => {
304
304
  const n = Number(el.value);
@@ -316,7 +316,7 @@ export class KashiSlider extends HTMLBase {
316
316
  track.style.setProperty("--_to", pct(this.hi));
317
317
  const out = this.querySelector(".k-slider__value");
318
318
  if (out)
319
- out.textContent = range ? `${this.fmt(this.lo)} تا ${this.fmt(this.hi)}` : this.fmt(this.hi);
319
+ out.textContent = range ? `${this.fmt(this.lo)}${msg().common.range}${this.fmt(this.hi)}` : this.fmt(this.hi);
320
320
  emit(this, "kashi-change", { value: this.value });
321
321
  }));
322
322
  }
@@ -362,7 +362,7 @@ export class KashiChipGroup extends HTMLBase {
362
362
  b.setAttribute("aria-pressed", String(b.hasAttribute("data-pressed") || b.getAttribute("aria-pressed") === "true"));
363
363
  b.insertAdjacentHTML("afterbegin", '<svg class="k-chip__check" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m5 10.5 3.2 3L15 7"/></svg>');
364
364
  if (b.dataset.count)
365
- b.insertAdjacentHTML("beforeend", `<span class="k-chip__count">${toFaDigits(b.dataset.count)}</span>`);
365
+ b.insertAdjacentHTML("beforeend", `<span class="k-chip__count">${num(this, b.dataset.count ?? "")}</span>`);
366
366
  });
367
367
  this.addEventListener("click", (e) => {
368
368
  const b = e.target.closest(".k-chip");
@@ -384,10 +384,10 @@ export class KashiChipGroup extends HTMLBase {
384
384
  }
385
385
  KashiChipGroup.observedAttributes = ["label", "single", "name"];
386
386
  const RULES = [
387
- [`حداقل ${toFaDigits(8)} نویسه`, (p) => p.length >= 8],
388
- ["حروف بزرگ و کوچک انگلیسی", (p) => /[a-z]/.test(p) && /[A-Z]/.test(p)],
389
- ["دست‌کم یک عدد", (p) => /\d/.test(p)],
390
- ["دست‌کم یک نماد، مثل ! یا @", (p) => /[^A-Za-z0-9\s؀-ۿ]/.test(p)],
387
+ [(m) => m.length(localeDigits() === "fa" ? toFaDigits(8) : "8"), (p) => p.length >= 8],
388
+ [(m) => m.cases, (p) => /[a-z]/.test(p) && /[A-Z]/.test(p)],
389
+ [(m) => m.digit, (p) => /\d/.test(p)],
390
+ [(m) => m.symbol, (p) => /[^A-Za-z0-9\s؀-ۿ]/.test(p)],
391
391
  ];
392
392
  /** قدرت رمز زیر فیلد رمز؛ با for="شناسهٔ فیلد" به آن وصل می‌شود و با هر تایپ به‌روز می‌شود */
393
393
  export class KashiPasswordStrength extends HTMLBase {
@@ -433,11 +433,12 @@ export class KashiPasswordStrength extends HTMLBase {
433
433
  }
434
434
  render(p) {
435
435
  const score = this.score(p);
436
- const levels = ["ضعیف", "متوسط", "خوب", "قوی"];
436
+ const P = msg().password;
437
+ const levels = P.levels;
437
438
  const persian = /[؀-ۿ]/.test(p);
438
- this.innerHTML = `<div class="k-strength" data-score="${score}"><div class="k-strength__bars" aria-hidden="true">${"<span class=\"k-strength__bar\"></span>".repeat(4)}</div><p class="k-strength__label" aria-live="polite" style="margin: 0">${score ? `قدرت رمز: <strong>${levels[score - 1]}</strong>` : ""}</p>${persian ? '<p class="k-hint k-hint--error" role="alert">رمز حروف فارسی دارد؛ شاید صفحه‌کلید روی فارسی مانده است.</p>' : ""}${this.getAttribute("show-rules") === "false" ? "" : `<ul class="k-strength__rules">${RULES.map(([label, t]) => {
439
+ this.innerHTML = `<div class="k-strength" data-score="${score}"><div class="k-strength__bars" aria-hidden="true">${"<span class=\"k-strength__bar\"></span>".repeat(4)}</div><p class="k-strength__label" aria-live="polite" style="margin: 0">${score ? esc(P.strength("\u0000")).replace("\u0000", `<strong>${esc(levels[score - 1])}</strong>`) : ""}</p>${persian ? `<p class="k-hint k-hint--error" role="alert">${esc(P.persian)}</p>` : ""}${this.getAttribute("show-rules") === "false" ? "" : `<ul class="k-strength__rules">${RULES.map(([label, t]) => {
439
440
  const met = t(p);
440
- return `<li class="k-strength__rule"${met ? ' data-met=""' : ""}>${met ? CHECK : '<svg viewBox="0 0 20 20" aria-hidden="true"><circle cx="10" cy="10" r="2.5" fill="currentColor"/></svg>'}<span>${label}<span class="k-sr-only">${met ? "، رعایت شده" : "، رعایت نشده"}</span></span></li>`;
441
+ return `<li class="k-strength__rule"${met ? ' data-met=""' : ""}>${met ? CHECK : '<svg viewBox="0 0 20 20" aria-hidden="true"><circle cx="10" cy="10" r="2.5" fill="currentColor"/></svg>'}<span>${esc(label(P))}<span class="k-sr-only">${met ? P.met : P.unmet}</span></span></li>`;
441
442
  }).join("")}</ul>`}</div>`;
442
443
  }
443
444
  }
@@ -519,13 +520,15 @@ class TextField extends HTMLBase {
519
520
  emit(this, "kashi-change", { value: next });
520
521
  }
521
522
  }
522
- const KINDS = { arabic: "حرف عربی", zwnj: "نیم‌فاصله", punctuation: "علامت", digits: "رقم", spacing: "فاصله" };
523
+ const KINDS = ["arabic", "zwnj", "punctuation", "digits", "spacing"];
523
524
  /** متن چندخطی با ویرایش نگارشی: ی و ک عربی، نیم‌فاصله، علامت‌ها و ارقام را می‌شمارد و با یک دکمه اصلاح می‌کند */
524
525
  export class KashiPersianTextarea extends TextField {
525
526
  constructor() {
526
527
  super(...arguments);
527
528
  this.multiline = true;
528
- this.defaultLabel = "متن";
529
+ }
530
+ get defaultLabel() {
531
+ return msg().persianInput.text;
529
532
  }
530
533
  render() {
531
534
  super.render();
@@ -547,9 +550,10 @@ export class KashiPersianTextarea extends TextField {
547
550
  return this.getAttribute("hint") ? esc(this.getAttribute("hint")) : null;
548
551
  const r = this.result();
549
552
  if (!r.count)
550
- return '<span class="k-textfix" data-state="clean"><span class="k-textfix__text">نگارش متن درست است.</span></span>';
551
- const summary = Object.keys(KINDS).filter((k) => r.fixes[k]).map((k) => `${toFaDigits(r.fixes[k])} ${KINDS[k]}`).join("، ");
552
- return `<span class="k-textfix" data-state="fix"><span class="k-textfix__text">${toFaDigits(r.count)} مورد قابل اصلاح: ${summary}</span><button type="button" class="k-btn k-btn--tertiary k-btn--xs" data-fix>اصلاح نگارش</button></span>`;
553
+ return `<span class="k-textfix" data-state="clean"><span class="k-textfix__text">${esc(msg().textFix.clean)}</span></span>`;
554
+ const T = msg().textFix;
555
+ const summary = KINDS.filter((k) => r.fixes[k]).map((k) => `${num(this, r.fixes[k])} ${T[k]}`).join(msg().common.list);
556
+ return `<span class="k-textfix" data-state="fix"><span class="k-textfix__text">${esc(T.count(num(this, r.count), summary))}</span><button type="button" class="k-btn k-btn--tertiary k-btn--xs" data-fix>${esc(T.fix)}</button></span>`;
553
557
  }
554
558
  }
555
559
  KashiPersianTextarea.observedAttributes = ["label", "hint", "error", "placeholder", "required", "disabled", "name", "value", "rows", "fix-on-blur", "fix-digits", "aria-label"];
@@ -558,7 +562,9 @@ export class KashiKeyboardFix extends TextField {
558
562
  constructor() {
559
563
  super(...arguments);
560
564
  this.multiline = false;
561
- this.defaultLabel = "متن";
565
+ }
566
+ get defaultLabel() {
567
+ return msg().persianInput.text;
562
568
  }
563
569
  render() {
564
570
  super.render();
@@ -573,7 +579,7 @@ export class KashiKeyboardFix extends TextField {
573
579
  const show = this.getAttribute("suggest") === "always" ? latin : looksLikeWrongLayout(t);
574
580
  if (!show)
575
581
  return this.getAttribute("hint") ? esc(this.getAttribute("hint")) : null;
576
- return `<span class="k-kbfix" role="status">منظورتان <button type="button" class="k-kbfix__btn" data-fix>«${esc(fixKeyboardLayout(t))}»</button> بود؟</span>`;
582
+ return `<span class="k-kbfix" role="status">${esc(msg().keyboardFix.before)} <button type="button" class="k-kbfix__btn" data-fix>«${esc(fixKeyboardLayout(t))}»</button>${lang() === "en" ? "" : " "}${esc(msg().keyboardFix.after)}</span>`;
577
583
  }
578
584
  }
579
585
  KashiKeyboardFix.observedAttributes = ["label", "hint", "error", "placeholder", "required", "disabled", "name", "value", "suggest", "aria-label"];
@@ -619,7 +625,7 @@ export class KashiTimeInput extends HTMLBase {
619
625
  return t ? formatTime(t) : null;
620
626
  }
621
627
  show(s) {
622
- return s ? (this.getAttribute("digits") === "latin" ? s : toFaDigits(s)) : "";
628
+ return s ? (digitsOf(this) === "latin" ? s : toFaDigits(s)) : "";
623
629
  }
624
630
  get lo() {
625
631
  const t = parseTime(this.getAttribute("min") ?? "");
@@ -632,8 +638,8 @@ export class KashiTimeInput extends HTMLBase {
632
638
  render() {
633
639
  const id = this.key;
634
640
  const ariaLabel = this.getAttribute("aria-label");
635
- const label = this.hasAttribute("label") ? this.getAttribute("label") : ariaLabel ? null : "ساعت";
636
- const fa = this.getAttribute("digits") !== "latin";
641
+ const label = this.hasAttribute("label") ? this.getAttribute("label") : ariaLabel ? null : msg().persianInput.time;
642
+ const fa = digitsOf(this) === "fa";
637
643
  const control = `<div class="k-input"><input id="${id}" class="k-input__control" type="text" inputmode="numeric" dir="ltr" autocomplete="off" placeholder="${esc(this.getAttribute("placeholder") ?? (fa ? "۰۹:۳۰" : "09:30"))}"${this.hasAttribute("required") ? " required" : ""}${this.hasAttribute("disabled") ? " disabled" : ""}${!label && ariaLabel ? ` aria-label="${esc(ariaLabel)}"` : ""}><span class="k-input__addon">${CLOCK}</span></div>`;
638
644
  this.querySelector(":scope > .k-field")?.remove();
639
645
  this.insertAdjacentHTML("afterbegin", fieldHTML({ id, label, required: this.hasAttribute("required"), control }));
@@ -680,11 +686,11 @@ export class KashiTimeInput extends HTMLBase {
680
686
  paint(syncText = true) {
681
687
  if (syncText)
682
688
  this.input.value = this.show(this.current);
683
- const msg = this.invalid === "range"
684
- ? `ساعت باید بین ${this.show(formatTime(fromMin(this.lo)))} و ${this.show(formatTime(fromMin(this.hi)))} باشد.`
685
- : this.invalid ? "ساعت معتبر نیست؛ آن را به شکل ۰۹:۳۰ وارد کنید." : null;
686
- this.input.setCustomValidity(msg ?? "");
687
- setMessages(this.querySelector(":scope > .k-field"), this.input, this.key, this.getAttribute("error") || msg, this.getAttribute("hint"));
689
+ const text = this.invalid === "range"
690
+ ? msg().invalid.timeRange(this.show(formatTime(fromMin(this.lo))), this.show(formatTime(fromMin(this.hi))))
691
+ : this.invalid ? msg().invalid.time : null;
692
+ this.input.setCustomValidity(text ?? "");
693
+ setMessages(this.querySelector(":scope > .k-field"), this.input, this.key, this.getAttribute("error") || text, this.getAttribute("hint"));
688
694
  syncHidden(this, this.getAttribute("name"), this.current ?? "");
689
695
  }
690
696
  }
@@ -735,8 +741,9 @@ export class KashiPlateInput extends HTMLBase {
735
741
  const p = this.plate;
736
742
  const off = this.hasAttribute("disabled") ? " disabled" : "";
737
743
  const seg = (key, len, aria, cls = "", first = false) => `<input${first ? ` id="${k}-first"` : ""} class="k-plate__seg ${cls}" data-key="${key}" data-len="${len}" inputmode="numeric" autocomplete="off" aria-label="${aria}" placeholder="${toFaDigits("0".repeat(len))}" value="${toFaDigits(p[key])}"${off}>`;
738
- const label = this.getAttribute("label") ?? "پلاک خودرو";
739
- const control = `<div class="k-plate" role="group" aria-label="${esc(label)}" data-type="${plateType(p.letter)}"><span class="k-plate__flag" aria-hidden="true"><span class="k-plate__flag-colors"></span>I.R.<br>IRAN</span>${seg("first", 2, "دو رقم اول پلاک", "", true)}<select class="k-plate__letter" data-key="letter" aria-label="حرف پلاک"${off}><option value="">–</option>${PLATE_LETTERS.map((l) => `<option value="${l}"${l === p.letter ? " selected" : ""}>${l === "ه" ? "هـ" : l}</option>`).join("")}</select>${seg("middle", 3, "سه رقم پلاک", "k-plate__seg--3")}<span class="k-plate__region"><span class="k-plate__region-label" aria-hidden="true">ایران</span>${seg("region", 2, "کد استان")}</span></div><span class="k-sr-only" aria-live="polite"></span>`;
744
+ const PL = msg().plate;
745
+ const label = this.getAttribute("label") ?? PL.label;
746
+ const control = `<div class="k-plate" role="group" aria-label="${esc(label)}" data-type="${plateType(p.letter)}"><span class="k-plate__flag" aria-hidden="true"><span class="k-plate__flag-colors"></span>I.R.<br>IRAN</span>${seg("first", 2, PL.first, "", true)}<select class="k-plate__letter" data-key="letter" aria-label="${esc(PL.letter)}"${off}><option value="">–</option>${PLATE_LETTERS.map((l) => `<option value="${l}"${l === p.letter ? " selected" : ""}>${l === "ه" ? "هـ" : l}</option>`).join("")}</select>${seg("middle", 3, PL.middle, "k-plate__seg--3")}<span class="k-plate__region"><span class="k-plate__region-label" aria-hidden="true">ایران</span>${seg("region", 2, PL.region)}</span></div><span class="k-sr-only" aria-live="polite"></span>`;
740
747
  this.querySelector(":scope > .k-field")?.remove();
741
748
  this.insertAdjacentHTML("afterbegin", fieldHTML({ id: `${k}-first`, label, control }));
742
749
  const parts = [...this.querySelectorAll("[data-key]")];
@@ -786,7 +793,7 @@ export class KashiPlateInput extends HTMLBase {
786
793
  group.dataset.type = plateType(p.letter);
787
794
  const complete = p.first.length === 2 && !!p.letter && p.middle.length === 3 && p.region.length === 2;
788
795
  const showInvalid = (this.touched || complete) && Object.values(p).some(Boolean) && !this.valid;
789
- const error = this.getAttribute("error") || (showInvalid ? "پلاک خودرو معتبر نیست." : null);
796
+ const error = this.getAttribute("error") || (showInvalid ? msg().invalid.plate : null);
790
797
  group.toggleAttribute("data-invalid", !!error);
791
798
  setMessages(this.querySelector(":scope > .k-field"), group, this.key, error, this.getAttribute("hint"));
792
799
  this.querySelector(".k-field > .k-sr-only").textContent = this.valid ? formatPlate(p) : "";
@@ -834,10 +841,10 @@ export class KashiInlineEdit extends HTMLBase {
834
841
  this.render();
835
842
  }
836
843
  render(focus = false) {
837
- const label = this.getAttribute("label") ?? "متن";
844
+ const label = this.getAttribute("label") ?? msg().persianInput.text;
838
845
  this.rendered = true;
839
846
  this.editing = false;
840
- this.innerHTML = `<span class="k-inline-edit"><button type="button" class="k-inline-edit__view" aria-label="${esc(`${label}: ${this.text || "خالی"}، ویرایش`)}">${this.text ? esc(this.text) : `<span class="k-inline-edit__placeholder">${esc(this.getAttribute("placeholder") ?? "خالی")}</span>`}${PENCIL}</button></span>`;
847
+ this.innerHTML = `<span class="k-inline-edit"><button type="button" class="k-inline-edit__view" aria-label="${esc(`${label}: ${this.text || msg().inlineEdit.empty}${msg().common.list}${msg().common.edit}`)}">${this.text ? esc(this.text) : `<span class="k-inline-edit__placeholder">${esc(this.getAttribute("placeholder") ?? msg().inlineEdit.empty)}</span>`}${PENCIL}</button></span>`;
841
848
  const view = this.querySelector("button");
842
849
  view.addEventListener("click", () => this.edit());
843
850
  if (focus)
@@ -845,9 +852,9 @@ export class KashiInlineEdit extends HTMLBase {
845
852
  }
846
853
  edit(error, draft = this.text) {
847
854
  this.editing = true;
848
- const label = this.getAttribute("label") ?? "متن";
855
+ const label = this.getAttribute("label") ?? msg().persianInput.text;
849
856
  const errId = uid("kashi-ie-err");
850
- this.innerHTML = `<span class="k-inline-edit"><span class="k-field" style="gap: 4px"><span class="k-input"${error ? ' data-state="invalid"' : ""}><input class="k-input__control" aria-label="${esc(label)}" placeholder="${esc(this.getAttribute("placeholder") ?? "")}"${error ? ` aria-invalid="true" aria-describedby="${errId}"` : ""}></span>${error ? `<span class="k-hint k-hint--error" id="${errId}">${esc(error)}</span>` : ""}</span><span class="k-inline-edit__actions"><button type="button" class="k-btn k-btn--primary k-btn--icon k-btn--sm" data-save aria-label="ثبت">${CHECK}</button><button type="button" class="k-btn k-btn--secondary k-btn--icon k-btn--sm" data-cancel aria-label="انصراف">${X}</button></span></span>`;
857
+ this.innerHTML = `<span class="k-inline-edit"><span class="k-field" style="gap: 4px"><span class="k-input"${error ? ' data-state="invalid"' : ""}><input class="k-input__control" aria-label="${esc(label)}" placeholder="${esc(this.getAttribute("placeholder") ?? "")}"${error ? ` aria-invalid="true" aria-describedby="${errId}"` : ""}></span>${error ? `<span class="k-hint k-hint--error" id="${errId}">${esc(error)}</span>` : ""}</span><span class="k-inline-edit__actions"><button type="button" class="k-btn k-btn--primary k-btn--icon k-btn--sm" data-save aria-label="${esc(msg().common.save)}">${CHECK}</button><button type="button" class="k-btn k-btn--secondary k-btn--icon k-btn--sm" data-cancel aria-label="${esc(msg().common.cancel)}">${X}</button></span></span>`;
851
858
  const input = this.querySelector("input");
852
859
  input.value = draft;
853
860
  input.focus();
@@ -883,7 +890,7 @@ export class KashiInlineEdit extends HTMLBase {
883
890
  }
884
891
  catch {
885
892
  this.text = prev;
886
- return this.edit("ذخیره نشد؛ دوباره امتحان کنید.", raw);
893
+ return this.edit(msg().inlineEdit.failed, raw);
887
894
  }
888
895
  }
889
896
  this.render(true);
package/dist/index.d.ts CHANGED
@@ -8,19 +8,25 @@ import { KashiDataTable } from "./table.js";
8
8
  import { KashiChipGroup, KashiInlineEdit, KashiKeyboardFix, KashiMultiSelect, KashiPasswordStrength, KashiPersianTextarea, KashiPlateInput, KashiSlider, KashiTimeInput } from "./forms.js";
9
9
  import { KashiColorPicker, KashiDateRangePicker, KashiFileUpload, KashiMonthPicker } from "./pickers.js";
10
10
  import { KashiActivityHeatmap, KashiBarChart, KashiBarList, KashiLineChart, KashiPieChart, KashiProportionBar, KashiSparkline } from "./charts.js";
11
+ import { KashiBanner, KashiInput, KashiTextarea } from "./basic.js";
12
+ import { KashiAppointmentPicker } from "./appointment.js";
11
13
  import { KashiCarousel, KashiCommandPalette, KashiContextMenu, KashiSideNav, KashiSplitter, KashiTour, KashiTreeView } from "./nav.js";
12
14
  import { KashiCalendar, KashiDatePicker } from "./calendar.js";
13
15
  import { KashiCountdown, KashiDate, KashiMoney, KashiRelativeTime } from "./display.js";
14
16
  import { KashiCopyButton, KashiDialog, KashiTabs, KashiTooltip } from "./overlay.js";
15
17
  import { KashiToaster, toast } from "./toast.js";
16
- export { KashiCardNumber, KashiIban, KashiLandline, KashiLegalId, KashiMobile, KashiNationalId, KashiPostalCode, KashiPrice, KashiOtp, KashiProvinceSelect, KashiCombobox, KashiCitySelect, KashiIranMap, KashiAddressForm, KashiCalendar, KashiDatePicker, KashiCountdown, KashiDate, KashiMoney, KashiRelativeTime, KashiCopyButton, KashiDialog, KashiTabs, KashiTooltip, KashiToaster, toast, KashiDropdownMenu, KashiPopover, KashiTagInput, KashiNumberInput, KashiRating, KashiPagination, KashiDataTable, KashiMultiSelect, KashiSlider, KashiChipGroup, KashiPasswordStrength, KashiPersianTextarea, KashiKeyboardFix, KashiTimeInput, KashiPlateInput, KashiInlineEdit, KashiDateRangePicker, KashiMonthPicker, KashiFileUpload, KashiColorPicker, KashiBarChart, KashiLineChart, KashiPieChart, KashiBarList, KashiProportionBar, KashiSparkline, KashiActivityHeatmap, KashiCommandPalette, KashiContextMenu, KashiCarousel, KashiTreeView, KashiTour, KashiSplitter, KashiSideNav, };
18
+ export { KashiCardNumber, KashiIban, KashiLandline, KashiLegalId, KashiMobile, KashiNationalId, KashiPostalCode, KashiPrice, KashiOtp, KashiProvinceSelect, KashiCombobox, KashiCitySelect, KashiIranMap, KashiAddressForm, KashiCalendar, KashiDatePicker, KashiCountdown, KashiDate, KashiMoney, KashiRelativeTime, KashiCopyButton, KashiDialog, KashiTabs, KashiTooltip, KashiToaster, toast, KashiDropdownMenu, KashiPopover, KashiTagInput, KashiNumberInput, KashiRating, KashiPagination, KashiDataTable, KashiMultiSelect, KashiSlider, KashiChipGroup, KashiPasswordStrength, KashiPersianTextarea, KashiKeyboardFix, KashiTimeInput, KashiPlateInput, KashiInlineEdit, KashiDateRangePicker, KashiMonthPicker, KashiFileUpload, KashiColorPicker, KashiBarChart, KashiLineChart, KashiPieChart, KashiBarList, KashiProportionBar, KashiSparkline, KashiActivityHeatmap, KashiCommandPalette, KashiContextMenu, KashiCarousel, KashiTreeView, KashiTour, KashiSplitter, KashiSideNav, KashiInput, KashiTextarea, KashiBanner, KashiAppointmentPicker, };
17
19
  export { KashiDigitsInput } from "./inputs.js";
20
+ /** زبان متن‌های داخلی همهٔ عنصرها: setLocale("en") */
21
+ export { setLocale } from "./base.js";
22
+ export { faMessages, enMessages } from "@kashi-ui/persian";
23
+ export type { KashiMessages, KashiMessagesInput, KashiLocale } from "@kashi-ui/persian";
18
24
  export type { ToastOptions, ToastTone } from "./toast.js";
19
25
  export type { ComboboxOption } from "./combobox.js";
20
26
  export type { TableColumn } from "./table.js";
21
27
  export type { CommandItem, TourStep, TreeNode } from "./nav.js";
22
28
  /** نام همهٔ عنصرها؛ مثلاً برای isCustomElement در Vue */
23
- export declare const KASHI_ELEMENTS: readonly ["kashi-national-id", "kashi-legal-id", "kashi-mobile", "kashi-landline", "kashi-card-number", "kashi-iban", "kashi-postal-code", "kashi-price", "kashi-otp", "kashi-combobox", "kashi-province-select", "kashi-city-select", "kashi-iran-map", "kashi-address-form", "kashi-calendar", "kashi-date-picker", "kashi-money", "kashi-date", "kashi-relative-time", "kashi-countdown", "kashi-dialog", "kashi-tabs", "kashi-tooltip", "kashi-copy-button", "kashi-toaster", "kashi-dropdown-menu", "kashi-popover", "kashi-tag-input", "kashi-number-input", "kashi-rating", "kashi-pagination", "kashi-data-table", "kashi-multi-select", "kashi-slider", "kashi-chip-group", "kashi-password-strength", "kashi-persian-textarea", "kashi-keyboard-fix", "kashi-time-input", "kashi-plate-input", "kashi-inline-edit", "kashi-date-range-picker", "kashi-month-picker", "kashi-file-upload", "kashi-color-picker", "kashi-bar-chart", "kashi-line-chart", "kashi-pie-chart", "kashi-bar-list", "kashi-proportion-bar", "kashi-sparkline", "kashi-activity-heatmap", "kashi-command-palette", "kashi-context-menu", "kashi-carousel", "kashi-tree-view", "kashi-tour", "kashi-splitter", "kashi-side-nav"];
29
+ export declare const KASHI_ELEMENTS: readonly ["kashi-national-id", "kashi-legal-id", "kashi-mobile", "kashi-landline", "kashi-card-number", "kashi-iban", "kashi-postal-code", "kashi-price", "kashi-otp", "kashi-combobox", "kashi-province-select", "kashi-city-select", "kashi-iran-map", "kashi-address-form", "kashi-calendar", "kashi-date-picker", "kashi-money", "kashi-date", "kashi-relative-time", "kashi-countdown", "kashi-dialog", "kashi-tabs", "kashi-tooltip", "kashi-copy-button", "kashi-toaster", "kashi-dropdown-menu", "kashi-popover", "kashi-tag-input", "kashi-number-input", "kashi-rating", "kashi-pagination", "kashi-data-table", "kashi-multi-select", "kashi-slider", "kashi-chip-group", "kashi-password-strength", "kashi-persian-textarea", "kashi-keyboard-fix", "kashi-time-input", "kashi-plate-input", "kashi-inline-edit", "kashi-date-range-picker", "kashi-month-picker", "kashi-file-upload", "kashi-color-picker", "kashi-bar-chart", "kashi-line-chart", "kashi-pie-chart", "kashi-bar-list", "kashi-proportion-bar", "kashi-sparkline", "kashi-activity-heatmap", "kashi-command-palette", "kashi-context-menu", "kashi-carousel", "kashi-tree-view", "kashi-tour", "kashi-splitter", "kashi-side-nav", "kashi-input", "kashi-textarea", "kashi-banner", "kashi-appointment-picker"];
24
30
  declare global {
25
31
  interface HTMLElementTagNameMap {
26
32
  "kashi-national-id": KashiNationalId;
@@ -82,5 +88,9 @@ declare global {
82
88
  "kashi-tour": KashiTour;
83
89
  "kashi-splitter": KashiSplitter;
84
90
  "kashi-side-nav": KashiSideNav;
91
+ "kashi-input": KashiInput;
92
+ "kashi-textarea": KashiTextarea;
93
+ "kashi-banner": KashiBanner;
94
+ "kashi-appointment-picker": KashiAppointmentPicker;
85
95
  }
86
96
  }
package/dist/index.js CHANGED
@@ -10,13 +10,18 @@ import { KashiDataTable } from "./table.js";
10
10
  import { KashiChipGroup, KashiInlineEdit, KashiKeyboardFix, KashiMultiSelect, KashiPasswordStrength, KashiPersianTextarea, KashiPlateInput, KashiSlider, KashiTimeInput, } from "./forms.js";
11
11
  import { KashiColorPicker, KashiDateRangePicker, KashiFileUpload, KashiMonthPicker } from "./pickers.js";
12
12
  import { KashiActivityHeatmap, KashiBarChart, KashiBarList, KashiLineChart, KashiPieChart, KashiProportionBar, KashiSparkline, } from "./charts.js";
13
+ import { KashiBanner, KashiInput, KashiTextarea } from "./basic.js";
14
+ import { KashiAppointmentPicker } from "./appointment.js";
13
15
  import { KashiCarousel, KashiCommandPalette, KashiContextMenu, KashiSideNav, KashiSplitter, KashiTour, KashiTreeView } from "./nav.js";
14
16
  import { KashiCalendar, KashiDatePicker } from "./calendar.js";
15
17
  import { KashiCountdown, KashiDate, KashiMoney, KashiRelativeTime } from "./display.js";
16
18
  import { KashiCopyButton, KashiDialog, KashiTabs, KashiTooltip } from "./overlay.js";
17
19
  import { KashiToaster, toast } from "./toast.js";
18
- export { KashiCardNumber, KashiIban, KashiLandline, KashiLegalId, KashiMobile, KashiNationalId, KashiPostalCode, KashiPrice, KashiOtp, KashiProvinceSelect, KashiCombobox, KashiCitySelect, KashiIranMap, KashiAddressForm, KashiCalendar, KashiDatePicker, KashiCountdown, KashiDate, KashiMoney, KashiRelativeTime, KashiCopyButton, KashiDialog, KashiTabs, KashiTooltip, KashiToaster, toast, KashiDropdownMenu, KashiPopover, KashiTagInput, KashiNumberInput, KashiRating, KashiPagination, KashiDataTable, KashiMultiSelect, KashiSlider, KashiChipGroup, KashiPasswordStrength, KashiPersianTextarea, KashiKeyboardFix, KashiTimeInput, KashiPlateInput, KashiInlineEdit, KashiDateRangePicker, KashiMonthPicker, KashiFileUpload, KashiColorPicker, KashiBarChart, KashiLineChart, KashiPieChart, KashiBarList, KashiProportionBar, KashiSparkline, KashiActivityHeatmap, KashiCommandPalette, KashiContextMenu, KashiCarousel, KashiTreeView, KashiTour, KashiSplitter, KashiSideNav, };
20
+ export { KashiCardNumber, KashiIban, KashiLandline, KashiLegalId, KashiMobile, KashiNationalId, KashiPostalCode, KashiPrice, KashiOtp, KashiProvinceSelect, KashiCombobox, KashiCitySelect, KashiIranMap, KashiAddressForm, KashiCalendar, KashiDatePicker, KashiCountdown, KashiDate, KashiMoney, KashiRelativeTime, KashiCopyButton, KashiDialog, KashiTabs, KashiTooltip, KashiToaster, toast, KashiDropdownMenu, KashiPopover, KashiTagInput, KashiNumberInput, KashiRating, KashiPagination, KashiDataTable, KashiMultiSelect, KashiSlider, KashiChipGroup, KashiPasswordStrength, KashiPersianTextarea, KashiKeyboardFix, KashiTimeInput, KashiPlateInput, KashiInlineEdit, KashiDateRangePicker, KashiMonthPicker, KashiFileUpload, KashiColorPicker, KashiBarChart, KashiLineChart, KashiPieChart, KashiBarList, KashiProportionBar, KashiSparkline, KashiActivityHeatmap, KashiCommandPalette, KashiContextMenu, KashiCarousel, KashiTreeView, KashiTour, KashiSplitter, KashiSideNav, KashiInput, KashiTextarea, KashiBanner, KashiAppointmentPicker, };
19
21
  export { KashiDigitsInput } from "./inputs.js";
22
+ /** زبان متن‌های داخلی همهٔ عنصرها: setLocale("en") */
23
+ export { setLocale } from "./base.js";
24
+ export { faMessages, enMessages } from "@kashi-ui/persian";
20
25
  /** نام همهٔ عنصرها؛ مثلاً برای isCustomElement در Vue */
21
26
  export const KASHI_ELEMENTS = [
22
27
  "kashi-national-id", "kashi-legal-id", "kashi-mobile", "kashi-landline", "kashi-card-number", "kashi-iban",
@@ -29,4 +34,5 @@ export const KASHI_ELEMENTS = [
29
34
  "kashi-date-range-picker", "kashi-month-picker", "kashi-file-upload", "kashi-color-picker",
30
35
  "kashi-bar-chart", "kashi-line-chart", "kashi-pie-chart", "kashi-bar-list", "kashi-proportion-bar", "kashi-sparkline", "kashi-activity-heatmap",
31
36
  "kashi-command-palette", "kashi-context-menu", "kashi-carousel", "kashi-tree-view", "kashi-tour", "kashi-splitter", "kashi-side-nav",
37
+ "kashi-input", "kashi-textarea", "kashi-banner", "kashi-appointment-picker",
32
38
  ];
package/dist/inputs.d.ts CHANGED
@@ -6,13 +6,13 @@ type Meta = {
6
6
  bank?: Bank;
7
7
  } | null;
8
8
  interface Kind {
9
- label: string;
9
+ label: () => string;
10
10
  maxDigits: number;
11
11
  format: (raw: string) => string;
12
12
  normalize?: (digits: string) => string;
13
13
  /** معتبر بودن مقدار کامل */
14
14
  valid: (raw: string) => boolean;
15
- invalidMessage: string;
15
+ invalidMessage: () => string;
16
16
  placeholder: {
17
17
  fa: string;
18
18
  latin: string;
@@ -52,7 +52,7 @@ export declare abstract class KashiDigitsInput extends HTMLBase {
52
52
  protected isValid(): boolean;
53
53
  focus(options?: FocusOptions): void;
54
54
  protected clean(text: string): string;
55
- private get digits();
55
+ protected get digits(): "fa" | "latin";
56
56
  private shown;
57
57
  private render;
58
58
  private onInput;