@shival99/z-ui 2.0.29 → 2.0.31

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 (46) hide show
  1. package/fesm2022/shival99-z-ui-components-z-calendar.mjs +294 -7
  2. package/fesm2022/shival99-z-ui-components-z-calendar.mjs.map +1 -1
  3. package/fesm2022/shival99-z-ui-components-z-chat.mjs +1 -1
  4. package/fesm2022/shival99-z-ui-components-z-chat.mjs.map +1 -1
  5. package/fesm2022/shival99-z-ui-components-z-drawer.mjs +16 -4
  6. package/fesm2022/shival99-z-ui-components-z-drawer.mjs.map +1 -1
  7. package/fesm2022/shival99-z-ui-components-z-editor.mjs +43 -25
  8. package/fesm2022/shival99-z-ui-components-z-editor.mjs.map +1 -1
  9. package/fesm2022/shival99-z-ui-components-z-gallery.mjs +457 -532
  10. package/fesm2022/shival99-z-ui-components-z-gallery.mjs.map +1 -1
  11. package/fesm2022/shival99-z-ui-components-z-kanban.mjs +1 -1
  12. package/fesm2022/shival99-z-ui-components-z-kanban.mjs.map +1 -1
  13. package/fesm2022/shival99-z-ui-components-z-media-player.mjs +658 -0
  14. package/fesm2022/shival99-z-ui-components-z-media-player.mjs.map +1 -0
  15. package/fesm2022/shival99-z-ui-components-z-modal.mjs +16 -4
  16. package/fesm2022/shival99-z-ui-components-z-modal.mjs.map +1 -1
  17. package/fesm2022/shival99-z-ui-components-z-qrcode.mjs +383 -0
  18. package/fesm2022/shival99-z-ui-components-z-qrcode.mjs.map +1 -0
  19. package/fesm2022/shival99-z-ui-components-z-scrollarea.mjs +131 -0
  20. package/fesm2022/shival99-z-ui-components-z-scrollarea.mjs.map +1 -0
  21. package/fesm2022/shival99-z-ui-components-z-show-more.mjs +121 -0
  22. package/fesm2022/shival99-z-ui-components-z-show-more.mjs.map +1 -0
  23. package/fesm2022/shival99-z-ui-components-z-table.mjs +988 -137
  24. package/fesm2022/shival99-z-ui-components-z-table.mjs.map +1 -1
  25. package/fesm2022/shival99-z-ui-components-z-tabs.mjs +135 -61
  26. package/fesm2022/shival99-z-ui-components-z-tabs.mjs.map +1 -1
  27. package/fesm2022/shival99-z-ui-components-z-tags.mjs +24 -14
  28. package/fesm2022/shival99-z-ui-components-z-tags.mjs.map +1 -1
  29. package/fesm2022/shival99-z-ui-components-z-toast.mjs +124 -31
  30. package/fesm2022/shival99-z-ui-components-z-toast.mjs.map +1 -1
  31. package/fesm2022/shival99-z-ui-i18n.mjs +70 -0
  32. package/fesm2022/shival99-z-ui-i18n.mjs.map +1 -1
  33. package/package.json +17 -1
  34. package/types/shival99-z-ui-components-z-calendar.d.ts +10 -5
  35. package/types/shival99-z-ui-components-z-drawer.d.ts +14 -2
  36. package/types/shival99-z-ui-components-z-editor.d.ts +13 -8
  37. package/types/shival99-z-ui-components-z-gallery.d.ts +97 -6
  38. package/types/shival99-z-ui-components-z-media-player.d.ts +123 -0
  39. package/types/shival99-z-ui-components-z-modal.d.ts +14 -2
  40. package/types/shival99-z-ui-components-z-qrcode.d.ts +76 -0
  41. package/types/shival99-z-ui-components-z-scrollarea.d.ts +46 -0
  42. package/types/shival99-z-ui-components-z-show-more.d.ts +36 -0
  43. package/types/shival99-z-ui-components-z-table.d.ts +59 -14
  44. package/types/shival99-z-ui-components-z-tabs.d.ts +10 -6
  45. package/types/shival99-z-ui-components-z-tags.d.ts +3 -0
  46. package/types/shival99-z-ui-components-z-toast.d.ts +35 -2
@@ -1915,6 +1915,7 @@ class ZCalendarComponent {
1915
1915
  return;
1916
1916
  }
1917
1917
  const input = event.target;
1918
+ this._formatInputValue(input);
1918
1919
  const { value } = input;
1919
1920
  this._preserveInputSelection(input);
1920
1921
  this._hasTypedDraft.set(true);
@@ -1953,6 +1954,272 @@ class ZCalendarComponent {
1953
1954
  _getExpectedFormatLength(format) {
1954
1955
  return format.replace(/\[.*?\]/g, ' ').length;
1955
1956
  }
1957
+ _parseFormatSegments(format) {
1958
+ const tokens = ['YYYY', 'MM', 'DD', 'HH', 'hh', 'mm', 'ss', 'A', 'a'];
1959
+ const segments = [];
1960
+ let currentIndex = 0;
1961
+ while (currentIndex < format.length) {
1962
+ let matchedToken = null;
1963
+ for (const token of tokens) {
1964
+ if (format.startsWith(token, currentIndex)) {
1965
+ matchedToken = token;
1966
+ break;
1967
+ }
1968
+ }
1969
+ if (matchedToken) {
1970
+ // Tách các token thành các loại tương ứng
1971
+ if (matchedToken === 'A' || matchedToken === 'a') {
1972
+ segments.push({ type: 'period', value: matchedToken });
1973
+ }
1974
+ if (matchedToken !== 'A' && matchedToken !== 'a') {
1975
+ segments.push({ type: 'digit', value: matchedToken });
1976
+ }
1977
+ currentIndex += matchedToken.length;
1978
+ continue;
1979
+ }
1980
+ const char = format[currentIndex];
1981
+ const lastSeg = segments[segments.length - 1];
1982
+ if (lastSeg && lastSeg.type === 'literal') {
1983
+ lastSeg.value += char;
1984
+ currentIndex += 1;
1985
+ continue;
1986
+ }
1987
+ segments.push({ type: 'literal', value: char });
1988
+ currentIndex += 1;
1989
+ }
1990
+ return segments;
1991
+ }
1992
+ _formatValueOnTyping(value, format) {
1993
+ // Không tự động format cho các định dạng tên tháng (như Tháng 6, June)
1994
+ if (format.includes('MMM') || format.includes('MMMM')) {
1995
+ return value;
1996
+ }
1997
+ const digitsCount = value.replace(/\D/g, '').length;
1998
+ // Nếu không có chữ số nào (ví dụ đang nhập chữ 'invalid-date'), trả về giá trị gốc để không xóa trắng textbox
1999
+ if (digitsCount === 0) {
2000
+ return value;
2001
+ }
2002
+ const segments = this._parseFormatSegments(format);
2003
+ const userGroups = value.match(/(\d+|[a-zA-Z]+)/g) || [];
2004
+ let result = '';
2005
+ let groupIndex = 0;
2006
+ for (let i = 0; i < segments.length; i++) {
2007
+ const seg = segments[i];
2008
+ if (seg.type === 'digit') {
2009
+ let group = userGroups[groupIndex] || '';
2010
+ groupIndex++;
2011
+ // Bỏ qua các nhóm không phải là chữ số khi cần khớp với segment dạng số
2012
+ while (group && !/^\d+$/.test(group)) {
2013
+ group = userGroups[groupIndex] || '';
2014
+ groupIndex++;
2015
+ }
2016
+ if (!group) {
2017
+ break;
2018
+ }
2019
+ // Giới hạn chiều dài của nhóm số theo định nghĩa segment
2020
+ const len = seg.value.length;
2021
+ const clampedGroup = group.slice(0, len);
2022
+ result += clampedGroup;
2023
+ // Nếu nhóm số đã nhập đủ độ dài segment, tự động chèn separator tiếp theo
2024
+ if (clampedGroup.length === len) {
2025
+ const nextSeg = segments[i + 1];
2026
+ if (nextSeg && nextSeg.type === 'literal') {
2027
+ result += nextSeg.value;
2028
+ i++;
2029
+ // Nếu người dùng đã gõ separator này rồi thì bỏ qua không lặp lại
2030
+ const nextGroup = userGroups[groupIndex];
2031
+ if (nextGroup && !/^[a-zA-Z0-9]+$/.test(nextGroup)) {
2032
+ groupIndex++;
2033
+ }
2034
+ }
2035
+ }
2036
+ continue;
2037
+ }
2038
+ if (seg.type === 'period') {
2039
+ let group = userGroups[groupIndex] || '';
2040
+ groupIndex++;
2041
+ while (group && !/^[a-zA-Z]+$/.test(group)) {
2042
+ group = userGroups[groupIndex] || '';
2043
+ groupIndex++;
2044
+ }
2045
+ if (!group) {
2046
+ break;
2047
+ }
2048
+ const isPM = /PM/i.test(group);
2049
+ if (seg.value === 'A') {
2050
+ result += isPM ? 'PM' : 'AM';
2051
+ }
2052
+ if (seg.value !== 'A') {
2053
+ result += isPM ? 'pm' : 'am';
2054
+ }
2055
+ continue;
2056
+ }
2057
+ if (seg.type === 'literal') {
2058
+ if (groupIndex < userGroups.length) {
2059
+ result += seg.value;
2060
+ }
2061
+ continue;
2062
+ }
2063
+ }
2064
+ return result;
2065
+ }
2066
+ _lastInputLengths = new Map();
2067
+ _formatInputValue(input) {
2068
+ const format = this._getParseFormat();
2069
+ if (format.includes('MMM')) {
2070
+ return;
2071
+ }
2072
+ const val = input.value;
2073
+ if (!this._lastInputLengths.has(input)) {
2074
+ this._lastInputLengths.set(input, val.length - 1);
2075
+ }
2076
+ const lastLen = this._lastInputLengths.get(input) || 0;
2077
+ this._lastInputLengths.set(input, val.length);
2078
+ if (val.length < lastLen) {
2079
+ return;
2080
+ }
2081
+ const formatted = this._formatValueOnTyping(val, format);
2082
+ if (formatted !== val) {
2083
+ const start = input.selectionStart;
2084
+ const end = input.selectionEnd;
2085
+ input.value = formatted;
2086
+ this._lastInputLengths.set(input, formatted.length);
2087
+ if (document.activeElement === input && start !== null && end !== null) {
2088
+ const diff = formatted.length - val.length;
2089
+ const newPos = start + diff;
2090
+ input.setSelectionRange(newPos, newPos);
2091
+ }
2092
+ }
2093
+ }
2094
+ _clampInputDateString(value, format) {
2095
+ // Không tự động clamp đối với các định dạng chữ chứa tên tháng
2096
+ if (format.includes('MMM') || format.includes('MMMM')) {
2097
+ return value;
2098
+ }
2099
+ const trimmed = value.trim();
2100
+ const digitsCount = trimmed.replace(/\D/g, '').length;
2101
+ // Nếu không có chữ số nào, trả về giá trị gốc để validation phát hiện lỗi và revert
2102
+ if (digitsCount === 0) {
2103
+ return value;
2104
+ }
2105
+ const segments = this._parseFormatSegments(format);
2106
+ const userGroups = trimmed.match(/(\d+|[a-zA-Z]+)/g) || [];
2107
+ let year = new Date().getFullYear();
2108
+ let month = 1;
2109
+ let day = 1;
2110
+ let hour = 0;
2111
+ let minute = 0;
2112
+ let second = 0;
2113
+ const parsedValues = new Map();
2114
+ let groupIndex = 0;
2115
+ for (const seg of segments) {
2116
+ if (seg.type === 'digit') {
2117
+ let group = userGroups[groupIndex] || '';
2118
+ groupIndex++;
2119
+ while (group && !/^\d+$/.test(group)) {
2120
+ group = userGroups[groupIndex] || '';
2121
+ groupIndex++;
2122
+ }
2123
+ if (group) {
2124
+ parsedValues.set(seg.value, parseInt(group, 10));
2125
+ }
2126
+ }
2127
+ }
2128
+ if (parsedValues.has('YYYY')) {
2129
+ year = parsedValues.get('YYYY');
2130
+ }
2131
+ if (parsedValues.has('MM')) {
2132
+ month = Math.max(1, Math.min(12, parsedValues.get('MM')));
2133
+ }
2134
+ if (parsedValues.has('HH')) {
2135
+ const val = parsedValues.get('HH');
2136
+ hour = val > 23 ? 0 : Math.max(0, val);
2137
+ }
2138
+ if (parsedValues.has('hh')) {
2139
+ hour = Math.max(1, Math.min(12, parsedValues.get('hh')));
2140
+ }
2141
+ if (parsedValues.has('mm')) {
2142
+ minute = Math.max(0, Math.min(59, parsedValues.get('mm')));
2143
+ }
2144
+ if (parsedValues.has('ss')) {
2145
+ second = Math.max(0, Math.min(59, parsedValues.get('ss')));
2146
+ }
2147
+ const maxDays = new Date(year, month, 0).getDate();
2148
+ if (parsedValues.has('DD')) {
2149
+ day = Math.max(1, Math.min(maxDays, parsedValues.get('DD')));
2150
+ }
2151
+ let result = '';
2152
+ groupIndex = 0;
2153
+ for (let i = 0; i < segments.length; i++) {
2154
+ const seg = segments[i];
2155
+ if (seg.type === 'digit') {
2156
+ let group = userGroups[groupIndex] || '';
2157
+ groupIndex++;
2158
+ while (group && !/^\d+$/.test(group)) {
2159
+ group = userGroups[groupIndex] || '';
2160
+ groupIndex++;
2161
+ }
2162
+ if (!group) {
2163
+ break;
2164
+ }
2165
+ const len = seg.value.length;
2166
+ let clampedVal = 0;
2167
+ if (seg.value === 'YYYY') {
2168
+ clampedVal = year;
2169
+ }
2170
+ if (seg.value === 'MM') {
2171
+ clampedVal = month;
2172
+ }
2173
+ if (seg.value === 'DD') {
2174
+ clampedVal = day;
2175
+ }
2176
+ if (seg.value === 'HH') {
2177
+ clampedVal = hour;
2178
+ }
2179
+ if (seg.value === 'hh') {
2180
+ clampedVal = hour;
2181
+ }
2182
+ if (seg.value === 'mm') {
2183
+ clampedVal = minute;
2184
+ }
2185
+ if (seg.value === 'ss') {
2186
+ clampedVal = second;
2187
+ }
2188
+ result += String(clampedVal).padStart(len, '0');
2189
+ const nextSeg = segments[i + 1];
2190
+ if (nextSeg && nextSeg.type === 'literal') {
2191
+ result += nextSeg.value;
2192
+ i++;
2193
+ }
2194
+ continue;
2195
+ }
2196
+ if (seg.type === 'period') {
2197
+ let group = userGroups[groupIndex] || '';
2198
+ groupIndex++;
2199
+ while (group && !/^[a-zA-Z]+$/.test(group)) {
2200
+ group = userGroups[groupIndex] || '';
2201
+ groupIndex++;
2202
+ }
2203
+ const isPM = group ? /PM/i.test(group) : /PM/i.test(trimmed);
2204
+ if (seg.value === 'A') {
2205
+ result += isPM ? 'PM' : 'AM';
2206
+ }
2207
+ if (seg.value !== 'A') {
2208
+ result += isPM ? 'pm' : 'am';
2209
+ }
2210
+ continue;
2211
+ }
2212
+ result += seg.value;
2213
+ }
2214
+ // Khôi phục AM/PM ở đuôi chuỗi nếu bị mất sau khi clamp
2215
+ const isPM = /PM/i.test(trimmed);
2216
+ const isAM = /AM/i.test(trimmed);
2217
+ if ((isPM || isAM) && !/am|pm/i.test(result)) {
2218
+ const hasSpace = /\s+(AM|PM)/i.test(trimmed);
2219
+ result += (hasSpace ? ' ' : '') + (isPM ? 'PM' : 'AM');
2220
+ }
2221
+ return result;
2222
+ }
1956
2223
  _preserveInputSelection(input) {
1957
2224
  const start = input.selectionStart;
1958
2225
  const end = input.selectionEnd;
@@ -1968,6 +2235,7 @@ class ZCalendarComponent {
1968
2235
  return;
1969
2236
  }
1970
2237
  const input = event.target;
2238
+ this._formatInputValue(input);
1971
2239
  const { value } = input;
1972
2240
  this._preserveInputSelection(input);
1973
2241
  this._hasTypedDraft.set(true);
@@ -1998,6 +2266,7 @@ class ZCalendarComponent {
1998
2266
  return;
1999
2267
  }
2000
2268
  const input = event.target;
2269
+ this._formatInputValue(input);
2001
2270
  const { value } = input;
2002
2271
  this._preserveInputSelection(input);
2003
2272
  this._hasTypedDraft.set(true);
@@ -2035,7 +2304,9 @@ class ZCalendarComponent {
2035
2304
  const input = event.target;
2036
2305
  const value = input.value.trim();
2037
2306
  const format = this._getParseFormat();
2038
- const date = parseDate(value, format, this.zLocale());
2307
+ const clamped = this._clampInputDateString(value, format);
2308
+ input.value = clamped;
2309
+ const date = parseDate(clamped, format, this.zLocale());
2039
2310
  if (!date) {
2040
2311
  this._cancelAndRestore();
2041
2312
  input.blur();
@@ -2074,7 +2345,9 @@ class ZCalendarComponent {
2074
2345
  const input = event.target;
2075
2346
  const value = input.value.trim();
2076
2347
  const format = this._getParseFormat();
2077
- const date = parseDate(value, format, this.zLocale());
2348
+ const clamped = this._clampInputDateString(value, format);
2349
+ input.value = clamped;
2350
+ const date = parseDate(clamped, format, this.zLocale());
2078
2351
  if (!date) {
2079
2352
  this._cancelAndRestore();
2080
2353
  input.blur();
@@ -2101,11 +2374,15 @@ class ZCalendarComponent {
2101
2374
  startEl.focus();
2102
2375
  }
2103
2376
  }
2104
- onInputFocus(_event) {
2377
+ onInputFocus(event) {
2105
2378
  this.isInputFocused.set(true);
2106
2379
  if (!this.isOpen()) {
2107
2380
  this._backupIfNeeded();
2108
2381
  }
2382
+ const input = event.target;
2383
+ if (input) {
2384
+ this._lastInputLengths.set(input, input.value.length);
2385
+ }
2109
2386
  }
2110
2387
  onInputBlur(event) {
2111
2388
  this.isInputFocused.set(false);
@@ -2186,8 +2463,10 @@ class ZCalendarComponent {
2186
2463
  if (this.isRangeMode()) {
2187
2464
  const parts = value.split(' - ');
2188
2465
  if (parts.length === 2) {
2189
- const start = parseDate(parts[0].trim(), format, this.zLocale());
2190
- const end = parseDate(parts[1].trim(), format, this.zLocale());
2466
+ const clampedStart = this._clampInputDateString(parts[0].trim(), format);
2467
+ const clampedEnd = this._clampInputDateString(parts[1].trim(), format);
2468
+ const start = parseDate(clampedStart, format, this.zLocale());
2469
+ const end = parseDate(clampedEnd, format, this.zLocale());
2191
2470
  if (start && end) {
2192
2471
  this._skipBlurHandler.set(true);
2193
2472
  const swapped = start > end;
@@ -2207,7 +2486,9 @@ class ZCalendarComponent {
2207
2486
  input.blur();
2208
2487
  return;
2209
2488
  }
2210
- const date = parseDate(value, format, this.zLocale());
2489
+ const clamped = this._clampInputDateString(value, format);
2490
+ input.value = clamped;
2491
+ const date = parseDate(clamped, format, this.zLocale());
2211
2492
  if (date) {
2212
2493
  this._skipBlurHandler.set(true);
2213
2494
  this._selectedDate.set(date);
@@ -2481,7 +2762,13 @@ class ZCalendarComponent {
2481
2762
  onOkClick() {
2482
2763
  if (this._hasTypedDraft() && !this.isRangeMode()) {
2483
2764
  const input = this.inputRef()?.nativeElement;
2484
- const date = parseDate(input?.value.trim() ?? '', this._getParseFormat(), this.zLocale());
2765
+ const rawVal = input?.value.trim() ?? '';
2766
+ const format = this._getParseFormat();
2767
+ const clamped = this._clampInputDateString(rawVal, format);
2768
+ if (input) {
2769
+ input.value = clamped;
2770
+ }
2771
+ const date = parseDate(clamped, format, this.zLocale());
2485
2772
  if (!date) {
2486
2773
  this._cancelAndRestore();
2487
2774
  if (input) {