design-system-next 2.26.9 → 2.26.12

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.
Binary file
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "design-system-next",
3
3
  "private": false,
4
- "version": "2.26.9",
4
+ "version": "2.26.12",
5
5
  "main": "./dist/design-system-next.umd.js",
6
6
  "module": "./dist/design-system-next.es.js",
7
7
  "types": "./dist/design-system-next.es.d.ts",
@@ -91,7 +91,37 @@ export const useInputContactNumber = (
91
91
  emit('getContactNumberErrors', []);
92
92
 
93
93
  if (value.length > 0) {
94
+ // Try to parse the number as user types
95
+ const original = value.trim();
96
+ const hasPlus = original.startsWith('+');
97
+ const normalizedNumber = hasPlus ? `+${original.replace(/[^0-9]/g, '')}` : original.replace(/\D/g, '');
98
+
99
+ let phoneNumber;
100
+
101
+ try {
102
+ phoneNumber = hasPlus
103
+ ? parsePhoneNumber(normalizedNumber)
104
+ : parsePhoneNumber(normalizedNumber, {
105
+ defaultCountry: selectedCountry.value.countryCode as CountryCode,
106
+ extract: false,
107
+ });
108
+ } catch {
109
+ phoneNumber = undefined;
110
+ }
111
+
112
+ // Emit parsed number even if incomplete, if it was parsed
113
+ if (phoneNumber && phoneNumber.isValid()) {
114
+ emit('getParsedInternationalNumber', phoneNumber.formatInternational());
115
+ } else if (normalizedNumber) {
116
+ // For incomplete numbers, emit what we have in international format prefix
117
+ const prefix = `+${selectedCountry.value.countryCallingCode}`;
118
+ emit('getParsedInternationalNumber', `${prefix} ${value.replace(/[^0-9]/g, '')}`);
119
+ }
120
+
94
121
  formatContactNumber();
122
+ } else {
123
+ // Emit empty string when input is cleared
124
+ emit('getParsedInternationalNumber', '');
95
125
  }
96
126
  };
97
127
 
@@ -109,6 +139,30 @@ export const useInputContactNumber = (
109
139
  countryCode: selectedCountry.value.countryCode,
110
140
  countryCallingCode: selectedCountry.value.countryCallingCode,
111
141
  });
142
+
143
+ // Emit parsed number with new country code if there's a value
144
+ if (formattedValue.value) {
145
+ const original = formattedValue.value.trim();
146
+ const normalizedNumber = original.replace(/\D/g, '');
147
+
148
+ let phoneNumber;
149
+
150
+ try {
151
+ phoneNumber = parsePhoneNumber(normalizedNumber, {
152
+ defaultCountry: selectedCountry.value.countryCode as CountryCode,
153
+ extract: false,
154
+ });
155
+ } catch {
156
+ phoneNumber = undefined;
157
+ }
158
+
159
+ if (phoneNumber && phoneNumber.isValid()) {
160
+ emit('getParsedInternationalNumber', phoneNumber.formatInternational().replace(/\s/g, ''));
161
+ } else if (normalizedNumber) {
162
+ const prefix = `+${selectedCountry.value.countryCallingCode}`;
163
+ emit('getParsedInternationalNumber', `${prefix}${normalizedNumber}`);
164
+ }
165
+ }
112
166
  };
113
167
 
114
168
  const formatContactNumber = () => {
@@ -146,6 +200,7 @@ export const useInputContactNumber = (
146
200
  formattedValue.value = formattedNumber;
147
201
 
148
202
  emit('getContactNumberErrors', []);
203
+ emit('getParsedInternationalNumber', phoneNumber.formatInternational());
149
204
  } else {
150
205
  emit('getContactNumberErrors', [
151
206
  {
@@ -20,7 +20,7 @@ export const inputCurrencyPropTypes = {
20
20
  type: String,
21
21
  default: '0.00',
22
22
  },
23
- preSelectedCurrency: {
23
+ currency: {
24
24
  type: String,
25
25
  default: 'PHP',
26
26
  },
@@ -17,16 +17,11 @@ interface InputCurrencyClasses {
17
17
  }
18
18
 
19
19
  export const useInputCurrency = (props: InputCurrencyPropTypes, emit: SetupContext<InputCurrencyEmitTypes>['emit']) => {
20
- const {
21
- id,
22
- preSelectedCurrency,
23
- disabledCountryCurrency,
24
- disabled,
25
- maxDecimals,
26
- minDecimals,
27
- disableRounding,
28
- baseValue,
29
- } = toRefs(props);
20
+ const { id, currency, disabledCountryCurrency, disabled, maxDecimals, minDecimals, disableRounding, baseValue } =
21
+ toRefs(props);
22
+
23
+ // Normalize currency to uppercase for case-insensitive support
24
+ const normalizedCurrency = computed(() => currency.value.toUpperCase());
30
25
 
31
26
  const inputCurrencyClasses: ComputedRef<InputCurrencyClasses> = computed(() => {
32
27
  const dropdownBaseClasses = classNames(
@@ -442,20 +437,23 @@ export const useInputCurrency = (props: InputCurrencyPropTypes, emit: SetupConte
442
437
 
443
438
  // Initialization of selected currency must occur AFTER currencyOptions is defined.
444
439
  const initCurrency = () => {
445
- const fallback = currencyOptions.find((c) => c.value === 'USD') || currencyOptions[0];
440
+ const fallback =
441
+ currencyOptions.find((c) => c.value === 'PHP') ||
442
+ currencyOptions.find((c) => c.value === 'USD') ||
443
+ currencyOptions[0];
446
444
 
447
- return currencyOptions.find((c) => c.value === preSelectedCurrency.value) || fallback;
445
+ return currencyOptions.find((c) => c.value === normalizedCurrency.value) || fallback;
448
446
  };
449
447
 
450
448
  const selected = ref(initCurrency());
451
449
  // #endregion - Set Currency Options
452
450
 
453
- watch(preSelectedCurrency, (code) => {
451
+ watch(normalizedCurrency, (code) => {
454
452
  if (code) handleSelectedCurrency(code);
455
453
  });
456
454
 
457
455
  onMounted(() => {
458
- handleSelectedCurrency(preSelectedCurrency.value);
456
+ handleSelectedCurrency(normalizedCurrency.value);
459
457
  if (modelValue.value && numericValue.value !== null) {
460
458
  modelValue.value = formatNumberForBlur(numericValue.value);
461
459
  emit('getCurrencyValue', numericValue.value);
@@ -613,6 +613,13 @@ export const useList = (props: ListPropTypes, emit: SetupContext<ListEmitTypes>[
613
613
  handleSearch();
614
614
  });
615
615
 
616
+ // Sync searchString (from prop) back to searchText (local state)
617
+ watch(searchString, (newVal) => {
618
+ if (searchText.value !== newVal) {
619
+ searchText.value = newVal;
620
+ }
621
+ });
622
+
616
623
  watch(
617
624
  apiSelectedList,
618
625
  () => {
@@ -153,48 +153,63 @@ export const useSelectLadderized = (
153
153
  if (disabled.value) return;
154
154
 
155
155
  wasCleared.value = true;
156
-
157
156
  inputText.value = '';
157
+ ladderizedSelectModel.value = [];
158
158
 
159
159
  emit('update:modelValue', []);
160
160
  };
161
161
 
162
- // Watch for changes in modelValue to update inputText
163
- watchDeep(
164
- ladderizedSelectModel,
165
- (newVal) => {
166
- if (isCustomInput.value) return;
167
-
168
- if (wasCleared.value) {
169
- inputText.value = '';
170
- wasCleared.value = false;
162
+ // Helper function to update input text from model value
163
+ const updateInputTextFromModel = (newVal: (string | number)[]) => {
164
+ if (isCustomInput.value) return;
171
165
 
172
- return;
173
- };
174
-
175
- if (Array.isArray(newVal) && newVal.length > 0) {
176
- // Treat the array as a single path for ladderized select
177
- let currentLevel = ladderizedSelectOptions.value;
166
+ if (wasCleared.value) {
167
+ inputText.value = '';
168
+ wasCleared.value = false;
169
+ return;
170
+ }
178
171
 
179
- const pathTexts: string[] = [];
172
+ if (Array.isArray(newVal) && newVal.length > 0) {
173
+ // Treat the array as a single path for ladderized select
174
+ let currentLevel = ladderizedSelectOptions.value;
175
+ const pathTexts: string[] = [];
180
176
 
181
- for (const value of newVal) {
182
- const found = currentLevel.find((item) => item.value === value);
177
+ for (const value of newVal) {
178
+ const found = currentLevel.find((item) => item.value === value);
183
179
 
184
- if (!found) break;
180
+ if (!found) break;
185
181
 
186
- pathTexts.push(found.text);
187
- currentLevel = found.sublevel || [];
188
- }
182
+ pathTexts.push(found.text);
183
+ currentLevel = found.sublevel || [];
184
+ }
189
185
 
186
+ // Only update if we successfully resolved all values in the path
187
+ if (pathTexts.length === newVal.length) {
190
188
  inputText.value = prependText.value
191
189
  ? pathTexts.slice().reverse().join(textSeperator.value)
192
190
  : pathTexts.join(textSeperator.value);
193
191
  }
192
+ } else if (Array.isArray(newVal) && newVal.length === 0) {
193
+ inputText.value = '';
194
+ }
195
+ };
196
+
197
+ // Watch for changes in modelValue to update inputText
198
+ watchDeep(
199
+ ladderizedSelectModel,
200
+ (newVal) => {
201
+ updateInputTextFromModel(newVal);
194
202
  },
195
203
  { immediate: true },
196
204
  );
197
205
 
206
+ // Watch for changes in options to re-render text when options load
207
+ watch(ladderizedSelectOptions, () => {
208
+ if (!wasCleared.value && ladderizedSelectModel.value && ladderizedSelectModel.value.length > 0) {
209
+ updateInputTextFromModel(ladderizedSelectModel.value);
210
+ }
211
+ });
212
+
198
213
  watch(ladderizedSelectPopperState, (newState) => {
199
214
  emit('popper-state', newState);
200
215
  });
@@ -107,6 +107,7 @@ export const useMultiSelect = (props: MultiSelectPropTypes, emit: SetupContext<M
107
107
 
108
108
  const inputText = ref<string | number>('');
109
109
  const chippedInputTextRef = ref(null);
110
+ const isSearching = ref<boolean>(false);
110
111
 
111
112
  const search = useVModel(props, 'searchValue', emit);
112
113
  const searchInput = ref<string>('');
@@ -204,9 +205,17 @@ export const useMultiSelect = (props: MultiSelectPropTypes, emit: SetupContext<M
204
205
  });
205
206
 
206
207
  hasUserSelected.value = true;
208
+
209
+ // Temporarily disable searching flag to allow inputText update
210
+ const wasSearching = isSearching.value;
211
+ isSearching.value = false;
212
+
207
213
  multiSelectModel.value = selectedValues;
208
214
 
209
- updateMultiSelectedItemsFromValue();
215
+ // Restore searching state if user was searching
216
+ if (wasSearching) {
217
+ isSearching.value = true;
218
+ }
210
219
 
211
220
  emit('get-selected-options', multiSelectedItems);
212
221
  };
@@ -252,6 +261,11 @@ export const useMultiSelect = (props: MultiSelectPropTypes, emit: SetupContext<M
252
261
  * Handles stringified objects and updates the input text accordingly.
253
262
  */
254
263
  const updateMultiSelectedItemsFromValue = () => {
264
+ // Don't update inputText if user is actively searching
265
+ if (isSearching.value) {
266
+ return;
267
+ }
268
+
255
269
  const values = normalizedValue.value;
256
270
 
257
271
  if (!values || !values.length) {
@@ -313,7 +327,7 @@ export const useMultiSelect = (props: MultiSelectPropTypes, emit: SetupContext<M
313
327
  inputText.value = `${values.length} items selected`;
314
328
  } else {
315
329
  // Safely get display text for each value
316
- inputText.value = values
330
+ const displayTexts = values
317
331
  .map((val) => {
318
332
  // Try to find the corresponding option for display text
319
333
  const found = multiSelectOptions.value.find((opt) => {
@@ -338,9 +352,12 @@ export const useMultiSelect = (props: MultiSelectPropTypes, emit: SetupContext<M
338
352
  }
339
353
  return optVal == v;
340
354
  });
341
- return found ? found.text : typeof val === 'string' || typeof val === 'number' ? String(val) : '';
355
+ // Only return text if found, otherwise return empty string
356
+ return found ? found.text : '';
342
357
  })
343
- .join(', ');
358
+ .filter((text) => text !== ''); // Filter out empty strings from not found items
359
+
360
+ inputText.value = displayTexts.length > 0 ? displayTexts.join(', ') : '';
344
361
  }
345
362
  }
346
363
 
@@ -390,6 +407,9 @@ export const useMultiSelect = (props: MultiSelectPropTypes, emit: SetupContext<M
390
407
  watch(searchInput, (newVal, oldVal) => {
391
408
  search.value = newVal;
392
409
 
410
+ // Track if user is actively searching
411
+ isSearching.value = newVal.length > 0;
412
+
393
413
  // Only emit search-string if value actually changed (not just modifier keys)
394
414
  // Modifier key presses alone won't change the input value
395
415
  if (newVal !== oldVal) {
@@ -422,6 +442,10 @@ export const useMultiSelect = (props: MultiSelectPropTypes, emit: SetupContext<M
422
442
 
423
443
  multiSelectPopperState.value = false;
424
444
 
445
+ // Clear search state when closing
446
+ isSearching.value = false;
447
+ searchInput.value = '';
448
+
425
449
  updateMultiSelectedItemsFromValue();
426
450
  },
427
451
  {