@genesislcap/foundation-ui 14.447.1 → 14.448.0-canary.wealth

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 (31) hide show
  1. package/dist/custom-elements.json +1534 -962
  2. package/dist/dts/date-picker/date-picker.d.ts +63 -0
  3. package/dist/dts/date-picker/date-picker.d.ts.map +1 -1
  4. package/dist/dts/date-picker/date-picker.template.d.ts.map +1 -1
  5. package/dist/dts/date-picker/date-picker.util.d.ts +37 -0
  6. package/dist/dts/date-picker/date-picker.util.d.ts.map +1 -0
  7. package/dist/dts/date-picker/index.d.ts +1 -0
  8. package/dist/dts/date-picker/index.d.ts.map +1 -1
  9. package/dist/dts/react.d.ts +9 -20
  10. package/dist/dts/search-bar/search-bar-combobox.d.ts +5 -6
  11. package/dist/dts/search-bar/search-bar-combobox.d.ts.map +1 -1
  12. package/dist/dts/search-bar/search-bar-combobox.styles.d.ts.map +1 -1
  13. package/dist/dts/search-bar/search-bar.d.ts +31 -0
  14. package/dist/dts/search-bar/search-bar.d.ts.map +1 -1
  15. package/dist/dts/search-bar/search-bar.styles.d.ts.map +1 -1
  16. package/dist/dts/search-bar/search-bar.template.d.ts.map +1 -1
  17. package/dist/dts/search-bar/search-bar.types.d.ts +1 -1
  18. package/dist/dts/search-bar/search-bar.types.d.ts.map +1 -1
  19. package/dist/esm/date-picker/date-picker.js +264 -17
  20. package/dist/esm/date-picker/date-picker.template.js +9 -1
  21. package/dist/esm/date-picker/date-picker.util.js +92 -0
  22. package/dist/esm/date-picker/index.js +1 -0
  23. package/dist/esm/search-bar/search-bar-combobox.js +31 -1
  24. package/dist/esm/search-bar/search-bar-combobox.styles.js +15 -0
  25. package/dist/esm/search-bar/search-bar-combobox.template.js +1 -1
  26. package/dist/esm/search-bar/search-bar.js +81 -1
  27. package/dist/esm/search-bar/search-bar.styles.js +0 -17
  28. package/dist/esm/search-bar/search-bar.template.js +27 -26
  29. package/dist/react.cjs +6 -25
  30. package/dist/react.mjs +5 -23
  31. package/package.json +19 -19
@@ -6,9 +6,11 @@ import dayjs from 'dayjs';
6
6
  import customParseFormat from 'dayjs/plugin/customParseFormat';
7
7
  import localeData from 'dayjs/plugin/localeData';
8
8
  import LocalizedFormat from 'dayjs/plugin/localizedFormat';
9
+ import { wasClickOutsideElement } from '../utils';
9
10
  import Calendar from './calendar';
10
11
  import { foundationDatePickerStyles as styles } from './date-picker.styles';
11
12
  import { foundationDatePickerTemplate as template } from './date-picker.template';
13
+ import { DATE_PICKER_VALUE_FORMAT, formatToPlaceholder, getBrowserLocale, getDisplayFormatForLang, hasDateValue, parseDatePickerValue, } from './date-picker.util';
12
14
  import Day from './day';
13
15
  import { getNextEnabledDay } from './day.util';
14
16
  export const foundationDatePickerShadowOptions = undefined;
@@ -31,7 +33,7 @@ export class DatePicker extends FoundationElement {
31
33
  * </rapid-date-picker>
32
34
  * ```
33
35
  */
34
- this.format = 'MM-DD-YYYY';
36
+ this.format = DATE_PICKER_VALUE_FORMAT;
35
37
  this.lang = 'en-US';
36
38
  this.visible = false;
37
39
  /**
@@ -56,53 +58,284 @@ export class DatePicker extends FoundationElement {
56
58
  * ```
57
59
  */
58
60
  this.disabledDaysOfWeek = [];
61
+ this.suppressValueChanged = false;
62
+ this.cachedFormat = DATE_PICKER_VALUE_FORMAT;
63
+ this.clickOutside = (e) => this.handleClickOutside(e);
64
+ this.keydownOutside = (e) => this.handleKeydownOutside(e);
59
65
  }
60
66
  formatChanged(oldValue, newValue) {
61
- if (newValue && this.calendar) {
67
+ if (!this.useLocaleFormat && newValue) {
68
+ this.cacheUserFormat(newValue);
69
+ }
70
+ if (newValue && this.calendar && hasDateValue(this.value)) {
62
71
  this.formatDate = dayjs(this.currentDate.Date).format(newValue);
63
72
  }
64
73
  }
74
+ langChanged() {
75
+ this.applyEffectiveLangChange();
76
+ }
77
+ useLocaleFormatChanged(oldValue, newValue) {
78
+ // Pre-mount: format/useLocaleFormat may be set in any order; let connectedCallback do the
79
+ // initial cache so we don't snapshot the default format before the `format` attribute is parsed.
80
+ if (!this.calendar) {
81
+ return;
82
+ }
83
+ if (newValue && !oldValue) {
84
+ this.cacheUserFormat(this.format);
85
+ }
86
+ else if (!newValue && oldValue) {
87
+ this.restoreUserFormat();
88
+ }
89
+ this.applyEffectiveLangChange();
90
+ }
65
91
  inlineCalendarChanged() {
92
+ if (this.inlineCalendar) {
93
+ document.removeEventListener('mousedown', this.clickOutside);
94
+ document.removeEventListener('keydown', this.keydownOutside);
95
+ }
96
+ else if (this.visible) {
97
+ document.addEventListener('mousedown', this.clickOutside);
98
+ document.addEventListener('keydown', this.keydownOutside);
99
+ }
66
100
  this.toggleVisibility();
67
101
  }
68
102
  hideWeekendsCalendarChanged() {
69
103
  this.toggleVisibility();
70
104
  }
71
105
  valueChanged(oldValue, newValue) {
72
- if (newValue && this.calendar) {
73
- const localeFormat = dayjs().localeData().longDateFormat('L');
74
- this.currentDate = new Day(dayjs(newValue, localeFormat).toDate(), this.lang);
75
- this.calendar.goToDate(this.currentDate.monthNumber, this.currentDate.year);
76
- this.formatDate = dayjs(this.currentDate.Date).format(this.format);
77
- this.updateHeaderText();
78
- this.monthList = this.getMonthDaysGrid();
106
+ if (this.suppressValueChanged) {
107
+ return;
108
+ }
109
+ if (!this.calendar) {
110
+ return;
111
+ }
112
+ if (!hasDateValue(newValue)) {
113
+ if (this.allowEmpty) {
114
+ this.clearToEmpty(false);
115
+ }
116
+ else {
117
+ this.resetToDefaultDate();
118
+ }
119
+ return;
79
120
  }
121
+ this.applyValue(newValue);
122
+ }
123
+ disconnectedCallback() {
124
+ document.removeEventListener('mousedown', this.clickOutside);
125
+ document.removeEventListener('keydown', this.keydownOutside);
126
+ super.disconnectedCallback();
80
127
  }
81
128
  connectedCallback() {
82
- var _a;
83
129
  super.connectedCallback();
84
130
  dayjs.extend(customParseFormat);
85
131
  dayjs.extend(LocalizedFormat);
86
132
  dayjs.extend(localeData);
87
133
  this.substringNumber = 3;
134
+ if (this.useLocaleFormat) {
135
+ this.cacheUserFormat(this.format);
136
+ this.applyLocaleFormat();
137
+ }
88
138
  const dateString = this.value;
89
- const dayjsDate = dateString ? dayjs(dateString, 'MM-DD-YYYY') : dayjs();
90
- let currentDate = new Day(dayjsDate.toDate(), this.lang);
139
+ if (this.allowEmpty && !hasDateValue(dateString)) {
140
+ this.initializeEmpty();
141
+ return;
142
+ }
143
+ if (hasDateValue(dateString)) {
144
+ this.applyValue(dateString);
145
+ return;
146
+ }
147
+ this.initializeWithDefaultDate();
148
+ }
149
+ /**
150
+ * Clears the selected date (only when `allow-empty` is enabled).
151
+ * @public
152
+ */
153
+ clear() {
154
+ if (!this.allowEmpty) {
155
+ return;
156
+ }
157
+ this.clearToEmpty(true);
158
+ }
159
+ /**
160
+ * @internal
161
+ */
162
+ get inputValue() {
163
+ return hasDateValue(this.value) ? this.formatDate : '';
164
+ }
165
+ /**
166
+ * @internal
167
+ */
168
+ get inputPlaceholder() {
169
+ var _a;
170
+ if (!this.allowEmpty || hasDateValue(this.value)) {
171
+ return '';
172
+ }
173
+ return ((_a = this.placeholder) === null || _a === void 0 ? void 0 : _a.trim()) || formatToPlaceholder(this.format);
174
+ }
175
+ /**
176
+ * Locale for display format and calendar labels: explicit `lang`, or browser when using locale format.
177
+ * @internal
178
+ */
179
+ get effectiveLang() {
180
+ if (this.useLocaleFormat && !this.hasAttribute('lang')) {
181
+ return getBrowserLocale();
182
+ }
183
+ return this.lang;
184
+ }
185
+ applyLocaleFormat() {
186
+ this.format = getDisplayFormatForLang(this.effectiveLang);
187
+ }
188
+ cacheUserFormat(format) {
189
+ const trimmed = format === null || format === void 0 ? void 0 : format.trim();
190
+ if (trimmed) {
191
+ this.cachedFormat = trimmed;
192
+ }
193
+ }
194
+ restoreUserFormat() {
195
+ this.format = this.cachedFormat;
196
+ }
197
+ applyEffectiveLangChange() {
198
+ var _a, _b;
199
+ if (!this.calendar) {
200
+ return;
201
+ }
202
+ if (this.useLocaleFormat) {
203
+ this.applyLocaleFormat();
204
+ }
205
+ const viewYear = this.calendar.year;
206
+ const viewMonth = this.calendar.month.number;
207
+ const selectedDate = (_b = (_a = this.currentDate) === null || _a === void 0 ? void 0 : _a.Date) !== null && _b !== void 0 ? _b : dayjs().toDate();
208
+ this.currentDate = new Day(selectedDate, this.effectiveLang);
209
+ this.calendar = new Calendar(viewYear, viewMonth, this.effectiveLang);
210
+ if (hasDateValue(this.value)) {
211
+ this.formatDate = dayjs(this.currentDate.Date).format(this.format);
212
+ }
213
+ this.updateHeaderText();
214
+ this.monthList = this.getMonthDaysGrid();
215
+ }
216
+ syncValueAttribute(value) {
217
+ this.suppressValueChanged = true;
218
+ this.value = value;
219
+ this.suppressValueChanged = false;
220
+ }
221
+ initializeEmpty() {
222
+ const viewDate = dayjs();
223
+ this.currentDate = new Day(viewDate.toDate(), this.effectiveLang);
224
+ this.calendar = new Calendar(this.currentDate.year, this.currentDate.monthNumber, this.effectiveLang);
225
+ this.formatDate = '';
226
+ this.syncValueAttribute('');
227
+ this.currentMonth = this.calendar.month.name;
228
+ this.currentYear = this.calendar.year;
229
+ this.monthList = this.getMonthDaysGrid();
230
+ }
231
+ initializeWithDefaultDate() {
232
+ this.resetToDefaultDate(true);
233
+ }
234
+ resetToDefaultDate(createCalendar = false) {
235
+ var _a;
236
+ let currentDate = new Day(dayjs().toDate(), this.effectiveLang);
91
237
  if ((_a = this.disabledDaysOfWeek) === null || _a === void 0 ? void 0 : _a.length) {
92
- currentDate = getNextEnabledDay(this.disabledDaysOfWeek, currentDate, this.lang);
238
+ currentDate = getNextEnabledDay(this.disabledDaysOfWeek, currentDate, this.effectiveLang);
93
239
  }
94
240
  this.currentDate = currentDate;
95
- this.calendar = new Calendar(this.currentDate.year, this.currentDate.monthNumber, this.lang);
96
- this.value = dayjs(this.currentDate.Date).format('MM-DD-YYYY');
241
+ if (createCalendar || !this.calendar) {
242
+ this.calendar = new Calendar(this.currentDate.year, this.currentDate.monthNumber, this.effectiveLang);
243
+ }
244
+ else {
245
+ this.calendar.goToDate(this.currentDate.monthNumber, this.currentDate.year);
246
+ }
247
+ this.formatDate = dayjs(this.currentDate.Date).format(this.format);
248
+ this.syncValueAttribute(dayjs(this.currentDate.Date).format(DATE_PICKER_VALUE_FORMAT));
97
249
  this.currentMonth = this.calendar.month.name;
98
250
  this.currentYear = this.calendar.year;
251
+ this.monthList = this.getMonthDaysGrid();
252
+ }
253
+ applyValue(dateString) {
254
+ const parsed = parseDatePickerValue(dateString, this.format);
255
+ if (!parsed) {
256
+ if (this.allowEmpty) {
257
+ this.clearToEmpty(false);
258
+ }
259
+ else {
260
+ this.resetToDefaultDate();
261
+ }
262
+ return;
263
+ }
264
+ // Honor the host's value verbatim. Disabled-day roll-forward only applies to the
265
+ // default "today" fallback (see `resetToDefaultDate`); programmatic writes should not
266
+ // be silently shifted, and user clicks on disabled day cells are blocked in the template.
267
+ this.currentDate = new Day(parsed.toDate(), this.effectiveLang);
268
+ if (!this.calendar) {
269
+ this.calendar = new Calendar(this.currentDate.year, this.currentDate.monthNumber, this.effectiveLang);
270
+ }
271
+ else {
272
+ this.calendar.goToDate(this.currentDate.monthNumber, this.currentDate.year);
273
+ }
99
274
  this.formatDate = dayjs(this.currentDate.Date).format(this.format);
275
+ this.syncValueAttribute(dayjs(this.currentDate.Date).format(DATE_PICKER_VALUE_FORMAT));
276
+ this.updateHeaderText();
100
277
  this.monthList = this.getMonthDaysGrid();
101
278
  }
279
+ /**
280
+ * Resets to the empty/cleared view.
281
+ * @param emitEvent - emit `value-changed` for user-driven clears (public `clear()`); skip for
282
+ * host-driven attribute writes since the host is the source of the change.
283
+ */
284
+ clearToEmpty(emitEvent) {
285
+ const viewDate = dayjs();
286
+ this.currentDate = new Day(viewDate.toDate(), this.effectiveLang);
287
+ if (this.calendar) {
288
+ this.calendar.goToDate(this.currentDate.monthNumber, this.currentDate.year);
289
+ this.updateHeaderText();
290
+ this.monthList = this.getMonthDaysGrid();
291
+ }
292
+ this.formatDate = '';
293
+ this.syncValueAttribute('');
294
+ if (emitEvent) {
295
+ this.$emit('value-changed', undefined);
296
+ }
297
+ }
102
298
  updateHeaderText() {
103
299
  this.currentMonth = this.calendar.month.name;
104
300
  this.currentYear = this.calendar.year;
105
301
  }
302
+ visibleChanged(_prev, next) {
303
+ if (this.inlineCalendar) {
304
+ return;
305
+ }
306
+ if (next) {
307
+ document.addEventListener('mousedown', this.clickOutside);
308
+ document.addEventListener('keydown', this.keydownOutside);
309
+ }
310
+ else {
311
+ document.removeEventListener('mousedown', this.clickOutside);
312
+ document.removeEventListener('keydown', this.keydownOutside);
313
+ }
314
+ }
315
+ handleKeydownOutside(event) {
316
+ if (this.inlineCalendar || !this.visible) {
317
+ return;
318
+ }
319
+ if (event.key === 'Escape') {
320
+ event.preventDefault();
321
+ this.closeCalendar();
322
+ }
323
+ }
324
+ handleClickOutside(event) {
325
+ if (this.inlineCalendar || !this.visible) {
326
+ return;
327
+ }
328
+ if (wasClickOutsideElement(event, this)) {
329
+ this.closeCalendar();
330
+ }
331
+ }
332
+ closeCalendar() {
333
+ if (!this.visible) {
334
+ return;
335
+ }
336
+ this.visible = false;
337
+ this.toggleVisibility();
338
+ }
106
339
  toggleCalendar() {
107
340
  this.visible = !this.visible;
108
341
  this.toggleVisibility();
@@ -115,6 +348,9 @@ export class DatePicker extends FoundationElement {
115
348
  this.calendarDropdownClasses = classNames(['visible', this.visible], this.position, ['inline', this.inlineCalendar], ['hide-weekends', this.hideWeekends]);
116
349
  }
117
350
  isSelectedDate(date) {
351
+ if (this.allowEmpty && !hasDateValue(this.value)) {
352
+ return false;
353
+ }
118
354
  return dayjs(date.Date).isSame(this.currentDate.Date, 'day');
119
355
  }
120
356
  isCurrentCalendarMonth() {
@@ -135,14 +371,16 @@ export class DatePicker extends FoundationElement {
135
371
  this.monthList = this.getMonthDaysGrid();
136
372
  }
137
373
  selectDay(day) {
138
- if (dayjs(day.Date).isSame(this.currentDate.Date))
374
+ const sameDayAsCurrent = dayjs(day.Date).isSame(this.currentDate.Date, 'day');
375
+ if (sameDayAsCurrent && hasDateValue(this.value)) {
139
376
  return;
377
+ }
140
378
  this.currentDate = day;
141
379
  if (day.monthNumber !== this.calendar.month.number) {
142
380
  this.prevMonth();
143
381
  }
144
382
  this.formatDate = dayjs(this.currentDate.Date).format(this.format);
145
- this.value = dayjs(day.Date).format('MM-DD-YYYY');
383
+ this.syncValueAttribute(dayjs(day.Date).format(DATE_PICKER_VALUE_FORMAT));
146
384
  this.$emit('value-changed', this.value);
147
385
  this.toggleCalendar();
148
386
  }
@@ -168,6 +406,9 @@ __decorate([
168
406
  __decorate([
169
407
  attr
170
408
  ], DatePicker.prototype, "lang", void 0);
409
+ __decorate([
410
+ attr({ attribute: 'use-locale-format', mode: 'boolean' })
411
+ ], DatePicker.prototype, "useLocaleFormat", void 0);
171
412
  __decorate([
172
413
  attr
173
414
  ], DatePicker.prototype, "visible", void 0);
@@ -183,6 +424,12 @@ __decorate([
183
424
  __decorate([
184
425
  attr
185
426
  ], DatePicker.prototype, "label", void 0);
427
+ __decorate([
428
+ attr({ attribute: 'allow-empty', mode: 'boolean' })
429
+ ], DatePicker.prototype, "allowEmpty", void 0);
430
+ __decorate([
431
+ attr
432
+ ], DatePicker.prototype, "placeholder", void 0);
186
433
  __decorate([
187
434
  attr
188
435
  ], DatePicker.prototype, "value", void 0);
@@ -5,7 +5,15 @@ const SUNDAY_INDEX = 1;
5
5
  const SATURDAY_INDEX = 7;
6
6
  const WEEKEND_DAY_INDICES = [SUNDAY_INDEX, SATURDAY_INDEX];
7
7
  export const getPrefixedDatePicker = (prefix) => html `
8
- <${prefix}-text-field data-test-id="date-picker" readonly :value="${(x) => x.formatDate}" part="date-toggle" class="date-toggle" @click="${(x) => x.toggleCalendar()}">
8
+ <${prefix}-text-field
9
+ data-test-id="date-picker"
10
+ readonly
11
+ :value="${(x) => x.inputValue}"
12
+ placeholder="${(x) => x.inputPlaceholder}"
13
+ part="date-toggle"
14
+ class="date-toggle"
15
+ @click="${(x) => x.toggleCalendar()}"
16
+ >
9
17
  ${(x) => x.label}
10
18
  <div class="input-icon-container" part="input-icon-container" slot="end"><${prefix}-icon variant="regular" name="calendar-alt" size="sm"></${prefix}-icon></div>
11
19
  </${prefix}-text-field>
@@ -0,0 +1,92 @@
1
+ import dayjs from 'dayjs';
2
+ import customParseFormat from 'dayjs/plugin/customParseFormat';
3
+ import localeData from 'dayjs/plugin/localeData';
4
+ import LocalizedFormat from 'dayjs/plugin/localizedFormat';
5
+ import 'dayjs/locale/en-gb';
6
+ dayjs.extend(customParseFormat);
7
+ dayjs.extend(localeData);
8
+ dayjs.extend(LocalizedFormat);
9
+ /**
10
+ * Maps BCP-47 tags to dayjs locale ids (lowercase, e.g. `fr-FR` → `fr-fr`).
11
+ * English variants map to dayjs bundles: `en-US` → `en`, `en-GB` → `en-gb`.
12
+ * @public
13
+ */
14
+ export function resolveDayjsLocale(lang) {
15
+ const normalized = ((lang === null || lang === void 0 ? void 0 : lang.trim()) || 'en').toLowerCase().replace(/_/g, '-');
16
+ if (normalized === 'en-us' || normalized === 'en') {
17
+ return 'en';
18
+ }
19
+ if (normalized === 'en-gb') {
20
+ return 'en-gb';
21
+ }
22
+ return normalized;
23
+ }
24
+ function dayjsLocaleWasApplied(requested, applied) {
25
+ if (requested === applied) {
26
+ return true;
27
+ }
28
+ const language = requested.split('-')[0];
29
+ return applied === language;
30
+ }
31
+ /**
32
+ * Browser BCP-47 locale (e.g. `en-GB`), or `en` when unavailable (SSR/tests).
33
+ * @public
34
+ */
35
+ export function getBrowserLocale() {
36
+ if (typeof navigator !== 'undefined' && navigator.language) {
37
+ return navigator.language;
38
+ }
39
+ return 'en';
40
+ }
41
+ /**
42
+ * Display format from dayjs locale `L` (e.g. en / en-US → MM/DD/YYYY, en-gb → DD/MM/YYYY).
43
+ * Falls back to `en` when the locale is not loaded in dayjs (import the matching `dayjs/locale/*` bundle).
44
+ * @public
45
+ */
46
+ export function getDisplayFormatForLang(lang = 'en') {
47
+ const locale = resolveDayjsLocale(lang);
48
+ const instance = dayjs().locale(locale);
49
+ const appliedLocale = instance.locale();
50
+ if (!dayjsLocaleWasApplied(locale, appliedLocale)) {
51
+ return dayjs().locale('en').localeData().longDateFormat('L') || 'MM/DD/YYYY';
52
+ }
53
+ return instance.localeData().longDateFormat('L') || 'MM/DD/YYYY';
54
+ }
55
+ /**
56
+ * Maps a dayjs-style display format to a lowercase placeholder hint (e.g. DD/MM/YYYY → dd/mm/yyyy).
57
+ * @public
58
+ */
59
+ export function formatToPlaceholder(format) {
60
+ return format
61
+ .replace(/YYYY/g, 'yyyy')
62
+ .replace(/YY(?!Y)/g, 'yy')
63
+ .replace(/DD/g, 'dd')
64
+ .replace(/D(?!D)/g, 'd')
65
+ .replace(/MM/g, 'mm')
66
+ .replace(/M(?!M)/g, 'm');
67
+ }
68
+ export function hasDateValue(value) {
69
+ return value !== null && value !== undefined && String(value).trim() !== '';
70
+ }
71
+ /**
72
+ * Internal wire format for the date picker's `value` attribute.
73
+ * Display formatting is independent (see `format` / `getDisplayFormatForLang`).
74
+ * @public
75
+ */
76
+ export const DATE_PICKER_VALUE_FORMAT = 'MM-DD-YYYY';
77
+ /**
78
+ * Strictly parses a date picker value (`displayFormat` or internal `DATE_PICKER_VALUE_FORMAT`). Returns null when invalid.
79
+ * @public
80
+ */
81
+ export function parseDatePickerValue(dateString, displayFormat) {
82
+ const trimmed = String(dateString).trim();
83
+ const display = dayjs(trimmed, displayFormat, true);
84
+ if (display.isValid()) {
85
+ return display;
86
+ }
87
+ const internal = dayjs(trimmed, DATE_PICKER_VALUE_FORMAT, true);
88
+ if (internal.isValid()) {
89
+ return internal;
90
+ }
91
+ return null;
92
+ }
@@ -1,3 +1,4 @@
1
1
  export * from './date-picker.styles';
2
2
  export * from './date-picker.template';
3
3
  export * from './date-picker';
4
+ export * from './date-picker.util';
@@ -1,6 +1,6 @@
1
1
  import { __decorate } from "tslib";
2
2
  import { Combobox } from '@microsoft/fast-components';
3
- import { attr } from '@microsoft/fast-element';
3
+ import { attr, observable } from '@microsoft/fast-element';
4
4
  import { foundationSearchBarComboboxStyles } from './search-bar-combobox.styles';
5
5
  import { foundationSearchBarComboboxTemplate } from './search-bar-combobox.template';
6
6
  import { COMBO_INPUT_MIN_LENGTH } from './search-bar.types';
@@ -10,6 +10,18 @@ import { COMBO_INPUT_MIN_LENGTH } from './search-bar.types';
10
10
  * @fires change - Fired when the combobox value changes
11
11
  * @fires inputdeleted - Fired when the input is cleared by the user
12
12
  */
13
+ const INPUT_LOCK_ALLOWED_KEYS = new Set([
14
+ 'Backspace',
15
+ 'Delete',
16
+ 'Tab',
17
+ 'Escape',
18
+ 'ArrowUp',
19
+ 'ArrowDown',
20
+ 'ArrowLeft',
21
+ 'ArrowRight',
22
+ 'Home',
23
+ 'End',
24
+ ]);
13
25
  export class SearchBarCombobox extends Combobox {
14
26
  constructor() {
15
27
  super(...arguments);
@@ -70,6 +82,14 @@ export class SearchBarCombobox extends Combobox {
70
82
  }
71
83
  keydownHandler(e) {
72
84
  const key = e.key;
85
+ if (this.inputLocked) {
86
+ const isModifier = e.ctrlKey || e.metaKey || e.altKey;
87
+ const isAllowed = INPUT_LOCK_ALLOWED_KEYS.has(key) || isModifier;
88
+ if (!isAllowed) {
89
+ e.preventDefault();
90
+ return false;
91
+ }
92
+ }
73
93
  switch (key) {
74
94
  case 'ArrowUp':
75
95
  case 'ArrowDown': {
@@ -103,6 +123,13 @@ export class SearchBarCombobox extends Combobox {
103
123
  }
104
124
  }
105
125
  inputHandler(e) {
126
+ if (this.inputLocked) {
127
+ this.control.value = '';
128
+ this.value = '';
129
+ this.open = false;
130
+ e.stopImmediatePropagation();
131
+ return;
132
+ }
106
133
  if (this.control.value.length >= this.minlength) {
107
134
  this.open = true;
108
135
  }
@@ -128,6 +155,9 @@ export class SearchBarCombobox extends Combobox {
128
155
  __decorate([
129
156
  attr
130
157
  ], SearchBarCombobox.prototype, "minlength", void 0);
158
+ __decorate([
159
+ observable
160
+ ], SearchBarCombobox.prototype, "inputLocked", void 0);
131
161
  export const foundationSearchBarComboboxShadowOptions = {
132
162
  delegatesFocus: true,
133
163
  mode: 'open',
@@ -23,4 +23,19 @@ export const foundationSearchBarComboboxStyles = (context, definition) => css `
23
23
  min-width: 150px;
24
24
  max-width: 169px;
25
25
  }
26
+
27
+ .input-locked .control,
28
+ :host(.input-locked) .control {
29
+ width: 0;
30
+ min-width: 0;
31
+ padding: 0;
32
+ margin: 0;
33
+ overflow: hidden;
34
+ flex: 0;
35
+ }
36
+
37
+ .input-locked .selected-value,
38
+ :host(.input-locked) .selected-value {
39
+ display: none;
40
+ }
26
41
  `;
@@ -4,7 +4,7 @@ export const foundationSearchBarComboboxTemplate = (context, definition) => html
4
4
  <template
5
5
  aria-disabled="${(x) => x.ariaDisabled}"
6
6
  autocomplete="${(x) => x.autocomplete}"
7
- class="${(x) => (x.open ? 'open' : '')} ${(x) => (x.disabled ? 'disabled' : '')} ${(x) => x.position} body"
7
+ class="${(x) => (x.open ? 'open' : '')} ${(x) => (x.disabled ? 'disabled' : '')} ${(x) => x.position} ${(x) => (x.inputLocked ? 'input-locked' : '')} body"
8
8
  ?open="${(x) => x.open}"
9
9
  tabindex="${(x) => (!x.disabled ? '0' : null)}"
10
10
  @click="${(x, c) => x.clickHandler(c.event)}"