q2-tecton-elements 1.69.0 → 1.70.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bundle-report.json +2249 -358
- package/dist/cjs/click-elsewhere_3.cjs.entry.js +2 -2
- package/dist/cjs/{index-D2LFCsNP.js → index-SpDCZABA.js} +2 -2
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/cjs/q2-action-group_2.cjs.entry.js +1 -1
- package/dist/cjs/q2-action-sheet.cjs.entry.js +2 -2
- package/dist/cjs/q2-badge_2.cjs.entry.js +11 -4
- package/dist/cjs/q2-btn_2.cjs.entry.js +6 -2
- package/dist/cjs/q2-calendar.cjs.entry.js +5 -3
- package/dist/cjs/q2-card-image.cjs.entry.js +8 -6
- package/dist/cjs/q2-card.cjs.entry.js +2 -2
- package/dist/cjs/q2-carousel-pane.cjs.entry.js +1 -1
- package/dist/cjs/q2-carousel.cjs.entry.js +1 -1
- package/dist/cjs/q2-chart-area.cjs.entry.js +1 -1
- package/dist/cjs/q2-chart-bar.cjs.entry.js +1 -1
- package/dist/cjs/q2-chart-donut.cjs.entry.js +2 -2
- package/dist/cjs/q2-checkbox-group.cjs.entry.js +1 -1
- package/dist/cjs/q2-checkbox_2.cjs.entry.js +4 -3
- package/dist/cjs/q2-context.cjs.entry.js +1 -1
- package/dist/cjs/q2-currency.cjs.entry.js +1 -1
- package/dist/cjs/q2-data-table.cjs.entry.js +6 -3
- package/dist/cjs/q2-detail.cjs.entry.js +2 -2
- package/dist/cjs/q2-dropdown-item.cjs.entry.js +1 -1
- package/dist/cjs/q2-dropdown.cjs.entry.js +3 -3
- package/dist/cjs/q2-editable-field.cjs.entry.js +12 -4
- package/dist/cjs/q2-file-picker.cjs.entry.js +1 -1
- package/dist/cjs/q2-icon.cjs.entry.js +1 -1
- package/dist/cjs/q2-item.cjs.entry.js +2 -2
- package/dist/cjs/q2-legend.cjs.entry.js +1 -1
- package/dist/cjs/q2-link_2.cjs.entry.js +2 -2
- package/dist/cjs/q2-loc.cjs.entry.js +20 -2
- package/dist/cjs/q2-message.cjs.entry.js +1 -1
- package/dist/cjs/q2-meter.cjs.entry.js +2 -2
- package/dist/cjs/q2-modal.cjs.entry.js +3 -3
- package/dist/cjs/q2-month-picker.cjs.entry.js +1 -1
- package/dist/cjs/q2-optgroup.cjs.entry.js +1 -1
- package/dist/cjs/q2-option.cjs.entry.js +1 -1
- package/dist/cjs/q2-otp.cjs.entry.js +1 -1
- package/dist/cjs/q2-pagination.cjs.entry.js +10 -6
- package/dist/cjs/q2-pill.cjs.entry.js +1 -1
- package/dist/cjs/q2-radio-group.cjs.entry.js +1 -1
- package/dist/cjs/q2-radio.cjs.entry.js +1 -1
- package/dist/cjs/q2-relative-time.cjs.entry.js +1 -1
- package/dist/cjs/q2-search.cjs.entry.js +109 -16
- package/dist/cjs/q2-section.cjs.entry.js +2 -2
- package/dist/cjs/q2-select.cjs.entry.js +36 -6
- package/dist/cjs/q2-stepper-pane.cjs.entry.js +1 -1
- package/dist/cjs/q2-stepper-vertical.cjs.entry.js +24 -18
- package/dist/cjs/q2-stepper.cjs.entry.js +5 -4
- package/dist/cjs/q2-surface.cjs.entry.js +95 -0
- package/dist/cjs/q2-tab-container.cjs.entry.js +2 -2
- package/dist/cjs/q2-tab-pane.cjs.entry.js +1 -1
- package/dist/cjs/q2-tecton-elements.cjs.js +1 -1
- package/dist/cjs/q2-textarea.cjs.entry.js +1 -1
- package/dist/cjs/q2-toast.cjs.entry.js +1 -1
- package/dist/cjs/q2-tooltip.cjs.entry.js +1 -1
- package/dist/cjs/tecton-tab-pane.cjs.entry.js +2 -2
- package/dist/collection/collection-manifest.json +1 -0
- package/dist/collection/components/q2-action-sheet/q2-action-sheet.css +1 -1
- package/dist/collection/components/q2-btn/q2-btn.css +32 -17
- package/dist/collection/components/q2-btn/q2-btn.js +6 -1
- package/dist/collection/components/q2-calendar/q2-calendar.js +24 -2
- package/dist/collection/components/q2-calendar/test/q2-calendar-test.vr.js +4 -0
- package/dist/collection/components/q2-card/q2-card.css +2 -2
- package/dist/collection/components/q2-card-image/q2-card-image.css +3 -0
- package/dist/collection/components/q2-card-image/q2-card-image.js +25 -23
- package/dist/collection/components/q2-chart-area/q2-chart-area.css +4 -0
- package/dist/collection/components/q2-chart-bar/q2-chart-bar.css +4 -0
- package/dist/collection/components/q2-chart-donut/q2-chart-donut.css +1 -1
- package/dist/collection/components/q2-checkbox/q2-checkbox.js +2 -1
- package/dist/collection/components/q2-currency/q2-currency.css +1 -1
- package/dist/collection/components/q2-data-table/q2-data-table.js +5 -2
- package/dist/collection/components/q2-detail/q2-detail.css +12 -12
- package/dist/collection/components/q2-dropdown/q2-dropdown.js +2 -2
- package/dist/collection/components/q2-editable-field/q2-editable-field.js +11 -3
- package/dist/collection/components/q2-input/q2-input.css +11 -1
- package/dist/collection/components/q2-input/q2-input.js +29 -2
- package/dist/collection/components/q2-input/test/q2-input-test.vr.js +8 -0
- package/dist/collection/components/q2-item/q2-item.css +10 -5
- package/dist/collection/components/q2-item/test/q2-item-test.vr.js +132 -0
- package/dist/collection/components/q2-legend/q2-legend.css +2 -2
- package/dist/collection/components/q2-list/q2-list.css +1 -1
- package/dist/collection/components/q2-loc/q2-loc.js +42 -1
- package/dist/collection/components/q2-message/q2-message.css +4 -0
- package/dist/collection/components/q2-meter/q2-meter.css +3 -3
- package/dist/collection/components/q2-modal/q2-modal.css +1 -1
- package/dist/collection/components/q2-modal/q2-modal.js +2 -2
- package/dist/collection/components/q2-otp/q2-otp.css +33 -0
- package/dist/collection/components/q2-otp/test/q2-otp-test.vr.js +83 -0
- package/dist/collection/components/q2-pagination/q2-pagination.js +9 -5
- package/dist/collection/components/q2-popover/q2-popover.css +2 -1
- package/dist/collection/components/q2-radio/q2-radio.css +2 -0
- package/dist/collection/components/q2-search/q2-search.css +30 -0
- package/dist/collection/components/q2-search/q2-search.js +108 -15
- package/dist/collection/components/q2-search/test/q2-search-test.vr.js +145 -0
- package/dist/collection/components/q2-section/q2-section.css +1 -1
- package/dist/collection/components/q2-select/q2-select.css +4 -2
- package/dist/collection/components/q2-select/q2-select.js +54 -4
- package/dist/collection/components/q2-select/test/q2-select-test.vr.js +5 -0
- package/dist/collection/components/q2-stepper/q2-stepper.css +2 -2
- package/dist/collection/components/q2-stepper/q2-stepper.js +3 -2
- package/dist/collection/components/q2-stepper-vertical/q2-stepper-vertical.css +2 -2
- package/dist/collection/components/q2-stepper-vertical/q2-stepper-vertical.js +22 -16
- package/dist/collection/components/q2-surface/q2-surface.css +348 -0
- package/dist/collection/components/q2-surface/q2-surface.js +381 -0
- package/dist/collection/components/q2-surface/test/q2-surface-test.vr.js +108 -0
- package/dist/collection/components/q2-tab-container/q2-tab-container.js +1 -1
- package/dist/collection/components/q2-tab-pane/q2-tab-pane.js +1 -1
- package/dist/collection/components/q2-tag/q2-tag.js +1 -1
- package/dist/collection/components/q2-toast/q2-toast.js +3 -1
- package/dist/collection/components/tecton-tab-pane/tecton-tab-pane.js +2 -2
- package/dist/collection/utils/index.js +2 -2
- package/dist/components/index.js +12 -10
- package/dist/components/index2.js +3 -3
- package/dist/components/q2-action-sheet.js +1 -1
- package/dist/components/q2-btn2.js +5 -1
- package/dist/components/q2-calendar.js +294 -290
- package/dist/components/q2-card-image.js +9 -6
- package/dist/components/q2-card.js +14 -14
- package/dist/components/q2-chart-donut.js +1 -1
- package/dist/components/q2-checkbox2.js +12 -12
- package/dist/components/q2-currency.js +1 -1
- package/dist/components/q2-data-table.js +4 -4
- package/dist/components/q2-detail.js +1 -1
- package/dist/components/q2-dropdown.js +8 -8
- package/dist/components/q2-editable-field.js +15 -5
- package/dist/components/q2-input2.js +46 -26
- package/dist/components/q2-item2.js +1 -1
- package/dist/components/q2-legend2.js +51 -51
- package/dist/components/q2-list2.js +1 -1
- package/dist/components/q2-loc.js +23 -8
- package/dist/components/q2-meter.js +10 -10
- package/dist/components/q2-modal.js +54 -54
- package/dist/components/q2-pagination.js +28 -27
- package/dist/components/q2-popover2.js +1 -1
- package/dist/components/q2-search.js +128 -71
- package/dist/components/q2-section.js +1 -1
- package/dist/components/q2-select2.js +25 -9
- package/dist/components/q2-stepper-vertical.js +72 -63
- package/dist/components/q2-stepper.js +73 -71
- package/dist/components/q2-surface.d.ts +11 -0
- package/dist/components/q2-surface.js +109 -0
- package/dist/components/q2-tab-container.js +12 -12
- package/dist/components/q2-tab-pane.js +6 -6
- package/dist/components/q2-tag2.js +5 -5
- package/dist/components/tecton-tab-pane.js +10 -10
- package/dist/esm/click-elsewhere_3.entry.js +2 -2
- package/dist/esm/{index-Bx4m6N0g.js → index-Cps4jSQM.js} +2 -2
- package/dist/esm/loader.js +1 -1
- package/dist/esm/q2-action-group_2.entry.js +1 -1
- package/dist/esm/q2-action-sheet.entry.js +2 -2
- package/dist/esm/q2-badge_2.entry.js +11 -4
- package/dist/esm/q2-btn_2.entry.js +6 -2
- package/dist/esm/q2-calendar.entry.js +5 -3
- package/dist/esm/q2-card-image.entry.js +8 -6
- package/dist/esm/q2-card.entry.js +2 -2
- package/dist/esm/q2-carousel-pane.entry.js +1 -1
- package/dist/esm/q2-carousel.entry.js +1 -1
- package/dist/esm/q2-chart-area.entry.js +1 -1
- package/dist/esm/q2-chart-bar.entry.js +1 -1
- package/dist/esm/q2-chart-donut.entry.js +2 -2
- package/dist/esm/q2-checkbox-group.entry.js +1 -1
- package/dist/esm/q2-checkbox_2.entry.js +4 -3
- package/dist/esm/q2-context.entry.js +1 -1
- package/dist/esm/q2-currency.entry.js +1 -1
- package/dist/esm/q2-data-table.entry.js +6 -3
- package/dist/esm/q2-detail.entry.js +2 -2
- package/dist/esm/q2-dropdown-item.entry.js +1 -1
- package/dist/esm/q2-dropdown.entry.js +3 -3
- package/dist/esm/q2-editable-field.entry.js +12 -4
- package/dist/esm/q2-file-picker.entry.js +1 -1
- package/dist/esm/q2-icon.entry.js +1 -1
- package/dist/esm/q2-item.entry.js +2 -2
- package/dist/esm/q2-legend.entry.js +1 -1
- package/dist/esm/q2-link_2.entry.js +2 -2
- package/dist/esm/q2-loc.entry.js +20 -2
- package/dist/esm/q2-message.entry.js +1 -1
- package/dist/esm/q2-meter.entry.js +2 -2
- package/dist/esm/q2-modal.entry.js +3 -3
- package/dist/esm/q2-month-picker.entry.js +1 -1
- package/dist/esm/q2-optgroup.entry.js +1 -1
- package/dist/esm/q2-option.entry.js +1 -1
- package/dist/esm/q2-otp.entry.js +1 -1
- package/dist/esm/q2-pagination.entry.js +10 -6
- package/dist/esm/q2-pill.entry.js +1 -1
- package/dist/esm/q2-radio-group.entry.js +1 -1
- package/dist/esm/q2-radio.entry.js +1 -1
- package/dist/esm/q2-relative-time.entry.js +1 -1
- package/dist/esm/q2-search.entry.js +109 -16
- package/dist/esm/q2-section.entry.js +2 -2
- package/dist/esm/q2-select.entry.js +36 -6
- package/dist/esm/q2-stepper-pane.entry.js +1 -1
- package/dist/esm/q2-stepper-vertical.entry.js +24 -18
- package/dist/esm/q2-stepper.entry.js +5 -4
- package/dist/esm/q2-surface.entry.js +93 -0
- package/dist/esm/q2-tab-container.entry.js +2 -2
- package/dist/esm/q2-tab-pane.entry.js +1 -1
- package/dist/esm/q2-tecton-elements.js +1 -1
- package/dist/esm/q2-textarea.entry.js +1 -1
- package/dist/esm/q2-toast.entry.js +1 -1
- package/dist/esm/q2-tooltip.entry.js +1 -1
- package/dist/esm/tecton-tab-pane.entry.js +2 -2
- package/dist/q2-tecton-elements/click-elsewhere_3.entry.js +2 -2
- package/dist/q2-tecton-elements/{index-Bx4m6N0g.js → index-Cps4jSQM.js} +3 -3
- package/dist/q2-tecton-elements/q2-action-group_2.entry.js +1 -1
- package/dist/q2-tecton-elements/q2-action-sheet.entry.js +2 -2
- package/dist/q2-tecton-elements/q2-badge_2.entry.js +51 -32
- package/dist/q2-tecton-elements/q2-btn_2.entry.js +6 -2
- package/dist/q2-tecton-elements/q2-calendar.entry.js +7 -4
- package/dist/q2-tecton-elements/q2-card-image.entry.js +65 -62
- package/dist/q2-tecton-elements/q2-card.entry.js +2 -2
- package/dist/q2-tecton-elements/q2-carousel-pane.entry.js +1 -1
- package/dist/q2-tecton-elements/q2-carousel.entry.js +1 -1
- package/dist/q2-tecton-elements/q2-chart-area.entry.js +54 -54
- package/dist/q2-tecton-elements/q2-chart-bar.entry.js +3 -3
- package/dist/q2-tecton-elements/q2-chart-donut.entry.js +7 -7
- package/dist/q2-tecton-elements/q2-checkbox-group.entry.js +1 -1
- package/dist/q2-tecton-elements/q2-checkbox_2.entry.js +18 -18
- package/dist/q2-tecton-elements/q2-context.entry.js +1 -1
- package/dist/q2-tecton-elements/q2-currency.entry.js +1 -1
- package/dist/q2-tecton-elements/q2-data-table.entry.js +50 -50
- package/dist/q2-tecton-elements/q2-detail.entry.js +2 -2
- package/dist/q2-tecton-elements/q2-dropdown-item.entry.js +1 -1
- package/dist/q2-tecton-elements/q2-dropdown.entry.js +16 -16
- package/dist/q2-tecton-elements/q2-editable-field.entry.js +15 -8
- package/dist/q2-tecton-elements/q2-file-picker.entry.js +1 -1
- package/dist/q2-tecton-elements/q2-icon.entry.js +1 -1
- package/dist/q2-tecton-elements/q2-item.entry.js +2 -2
- package/dist/q2-tecton-elements/q2-legend.entry.js +1 -1
- package/dist/q2-tecton-elements/q2-link_2.entry.js +2 -2
- package/dist/q2-tecton-elements/q2-loc.entry.js +20 -6
- package/dist/q2-tecton-elements/q2-message.entry.js +1 -1
- package/dist/q2-tecton-elements/q2-meter.entry.js +2 -2
- package/dist/q2-tecton-elements/q2-modal.entry.js +55 -55
- package/dist/q2-tecton-elements/q2-month-picker.entry.js +1 -1
- package/dist/q2-tecton-elements/q2-optgroup.entry.js +1 -1
- package/dist/q2-tecton-elements/q2-option.entry.js +7 -7
- package/dist/q2-tecton-elements/q2-otp.entry.js +1 -1
- package/dist/q2-tecton-elements/q2-pagination.entry.js +25 -24
- package/dist/q2-tecton-elements/q2-pill.entry.js +1 -1
- package/dist/q2-tecton-elements/q2-radio-group.entry.js +1 -1
- package/dist/q2-tecton-elements/q2-radio.entry.js +1 -1
- package/dist/q2-tecton-elements/q2-relative-time.entry.js +1 -1
- package/dist/q2-tecton-elements/q2-search.entry.js +118 -61
- package/dist/q2-tecton-elements/q2-section.entry.js +2 -2
- package/dist/q2-tecton-elements/q2-select.entry.js +25 -10
- package/dist/q2-tecton-elements/q2-stepper-pane.entry.js +1 -1
- package/dist/q2-tecton-elements/q2-stepper-vertical.entry.js +75 -66
- package/dist/q2-tecton-elements/q2-stepper.entry.js +47 -45
- package/dist/q2-tecton-elements/q2-surface.entry.js +89 -0
- package/dist/q2-tecton-elements/q2-tab-container.entry.js +13 -13
- package/dist/q2-tecton-elements/q2-tab-pane.entry.js +2 -2
- package/dist/q2-tecton-elements/q2-tecton-elements.esm.js +1 -1
- package/dist/q2-tecton-elements/q2-textarea.entry.js +1 -1
- package/dist/q2-tecton-elements/q2-toast.entry.js +5 -5
- package/dist/q2-tecton-elements/q2-tooltip.entry.js +8 -8
- package/dist/q2-tecton-elements/tecton-tab-pane.entry.js +6 -6
- package/dist/types/components/q2-calendar/q2-calendar.d.ts +2 -0
- package/dist/types/components/q2-card-image/q2-card-image.d.ts +5 -5
- package/dist/types/components/q2-editable-field/q2-editable-field.d.ts +1 -0
- package/dist/types/components/q2-input/q2-input.d.ts +3 -0
- package/dist/types/components/q2-item/test/q2-item-test.vr.d.ts +1 -0
- package/dist/types/components/q2-loc/q2-loc.d.ts +6 -0
- package/dist/types/components/q2-modal/q2-modal.d.ts +1 -1
- package/dist/types/components/q2-otp/test/q2-otp-test.vr.d.ts +1 -0
- package/dist/types/components/q2-search/q2-search.d.ts +7 -0
- package/dist/types/components/q2-search/test/q2-search-test.vr.d.ts +1 -0
- package/dist/types/components/q2-select/q2-select.d.ts +4 -0
- package/dist/types/components/q2-stepper-vertical/q2-stepper-vertical.d.ts +2 -1
- package/dist/types/components/q2-surface/q2-surface.d.ts +54 -0
- package/dist/types/components/q2-surface/test/q2-surface-test.vr.d.ts +1 -0
- package/dist/types/components/q2-toast/q2-toast.d.ts +3 -1
- package/dist/types/components.d.ts +259 -13
- package/dist/types/utils/index.d.ts +3 -1
- package/package.json +4 -3
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Fragment, h, } from "@stencil/core";
|
|
2
|
-
import { loc, overrideFocus, waitForNextPaint } from "../../utils";
|
|
2
|
+
import { isEventFromElement, loc, overrideFocus, waitForNextPaint } from "../../utils";
|
|
3
3
|
/**
|
|
4
4
|
* @name Search
|
|
5
5
|
* @category Forms
|
|
@@ -83,6 +83,7 @@ export class Q2Search {
|
|
|
83
83
|
*/
|
|
84
84
|
this.showSelectedToggle = false;
|
|
85
85
|
this.clearAll = () => {
|
|
86
|
+
this.clearSelectedDisplay();
|
|
86
87
|
const { multiple } = this;
|
|
87
88
|
this.value = '';
|
|
88
89
|
this.selectedOptions = [];
|
|
@@ -101,7 +102,7 @@ export class Q2Search {
|
|
|
101
102
|
this.tctInput.emit({ query: '' });
|
|
102
103
|
};
|
|
103
104
|
this.handleSelectionChanges = (detail) => {
|
|
104
|
-
var _a, _b, _c, _d, _e
|
|
105
|
+
var _a, _b, _c, _d, _e;
|
|
105
106
|
const { multiple } = this;
|
|
106
107
|
if (multiple) {
|
|
107
108
|
const values = (_a = detail.values) !== null && _a !== void 0 ? _a : [];
|
|
@@ -123,6 +124,10 @@ export class Q2Search {
|
|
|
123
124
|
// Re-clicking the already-selected single-select option closes the popover
|
|
124
125
|
// with no state change and no `tctChange`.
|
|
125
126
|
if (value === this.value && value !== '') {
|
|
127
|
+
const reSelected = this.optionElements.find(o => o.value === value);
|
|
128
|
+
this.searchText = this.optionDisplayText(reSelected, value);
|
|
129
|
+
this.isShowingSelectionDisplay = true;
|
|
130
|
+
this.checkSelectedDisplay();
|
|
126
131
|
// Focus before close so the focus event fires while open===true, which
|
|
127
132
|
// causes onFocus to skip openDropdown (it's already open at that point).
|
|
128
133
|
(_d = this.innerInputField) === null || _d === void 0 ? void 0 : _d.focus();
|
|
@@ -131,12 +136,13 @@ export class Q2Search {
|
|
|
131
136
|
}
|
|
132
137
|
this.value = value;
|
|
133
138
|
const selected = this.optionElements.find(o => o.value === value);
|
|
134
|
-
const display =
|
|
139
|
+
const display = this.optionDisplayText(selected, value);
|
|
135
140
|
this.searchText = display;
|
|
136
141
|
this.isShowingSelectionDisplay = true;
|
|
142
|
+
this.checkSelectedDisplay();
|
|
137
143
|
// Focus before close: the focus event fires while open===true so onFocus's
|
|
138
144
|
// openDropdown call is a no-op, then closeDropdown brings us to closed+focused.
|
|
139
|
-
(
|
|
145
|
+
(_e = this.innerInputField) === null || _e === void 0 ? void 0 : _e.focus();
|
|
140
146
|
this.closeDropdown();
|
|
141
147
|
this.tctChange.emit({
|
|
142
148
|
value,
|
|
@@ -154,6 +160,8 @@ export class Q2Search {
|
|
|
154
160
|
this.inputInputHandler = (event) => {
|
|
155
161
|
event.stopPropagation();
|
|
156
162
|
const next = event.detail.value;
|
|
163
|
+
if (this.isShowingSelectionDisplay)
|
|
164
|
+
this.clearSelectedDisplay();
|
|
157
165
|
// Preserve `value` while the user types — they're searching, not deselecting.
|
|
158
166
|
// `handleSelectionChanges` updates value if they pick a different option,
|
|
159
167
|
// and `revertToSelectedDisplay` restores the display on blur.
|
|
@@ -208,6 +216,17 @@ export class Q2Search {
|
|
|
208
216
|
event.stopPropagation();
|
|
209
217
|
this.handleSelectionChanges(event.detail);
|
|
210
218
|
};
|
|
219
|
+
this.onSelectedDisplayMousedown = (event) => {
|
|
220
|
+
var _a;
|
|
221
|
+
event.preventDefault();
|
|
222
|
+
event.stopPropagation();
|
|
223
|
+
this.isShowingSelectionDisplay = false;
|
|
224
|
+
this.clearSelectedDisplay();
|
|
225
|
+
if (this.value)
|
|
226
|
+
(_a = this.innerInputField) === null || _a === void 0 ? void 0 : _a.select();
|
|
227
|
+
if (!this.open)
|
|
228
|
+
this.openDropdown();
|
|
229
|
+
};
|
|
211
230
|
this.onViewportResize = () => {
|
|
212
231
|
if (!this.open || !this.popoverAlignment)
|
|
213
232
|
return;
|
|
@@ -248,19 +267,27 @@ export class Q2Search {
|
|
|
248
267
|
// #endregion
|
|
249
268
|
// #region Listeners
|
|
250
269
|
onFocus(event) {
|
|
251
|
-
var _a, _b, _c;
|
|
270
|
+
var _a, _b, _c, _d;
|
|
271
|
+
// Delegate programmatic focus from the host to the inner input
|
|
272
|
+
if (event && isEventFromElement(event, this.hostElement)) {
|
|
273
|
+
(_a = this.innerInputField) === null || _a === void 0 ? void 0 : _a.focus();
|
|
274
|
+
}
|
|
252
275
|
// Ignore focus that originates inside the popover (e.g., tabbing into a slotted
|
|
253
276
|
// popover-bottom action button). Without this gate, the focus event bubbles up and
|
|
254
277
|
// re-opens a just-closed popover as the user is trying to leave it.
|
|
255
278
|
const path = typeof (event === null || event === void 0 ? void 0 : event.composedPath) === 'function' ? event.composedPath() : [];
|
|
256
|
-
const target = ((
|
|
257
|
-
if (target && ((
|
|
279
|
+
const target = ((_b = path[0]) !== null && _b !== void 0 ? _b : event === null || event === void 0 ? void 0 : event.target);
|
|
280
|
+
if (target && ((_c = this.popoverElement) === null || _c === void 0 ? void 0 : _c.contains(target)))
|
|
258
281
|
return;
|
|
259
282
|
this.inputFocused = true;
|
|
260
|
-
|
|
283
|
+
// Only switch away from the selection display when the user actively re-engages the
|
|
284
|
+
// field (popover is closed). During the post-selection focus that closes the popover,
|
|
285
|
+
// `open` is still true — clearing here would immediately discard the rich display.
|
|
286
|
+
if (this.isShowingSelectionDisplay && !this.open) {
|
|
261
287
|
// Clear the flag before mutating searchText so the filter watcher runs against the
|
|
262
288
|
// new query, not the stale "showing a selection" guard.
|
|
263
289
|
this.isShowingSelectionDisplay = false;
|
|
290
|
+
this.clearSelectedDisplay();
|
|
264
291
|
if (this.multiple) {
|
|
265
292
|
// Multi-select always opens to a fresh search after a selection.
|
|
266
293
|
this.searchText = '';
|
|
@@ -268,7 +295,7 @@ export class Q2Search {
|
|
|
268
295
|
else if (this.value) {
|
|
269
296
|
// Single-select: pre-select the displayed text so the next keystroke replaces it
|
|
270
297
|
// — typeahead pattern used by Material Autocomplete, Headless UI Combobox, etc.
|
|
271
|
-
(
|
|
298
|
+
(_d = this.innerInputField) === null || _d === void 0 ? void 0 : _d.select();
|
|
272
299
|
}
|
|
273
300
|
}
|
|
274
301
|
if (!this.open)
|
|
@@ -357,6 +384,7 @@ export class Q2Search {
|
|
|
357
384
|
* Does not emit `tctChange`.
|
|
358
385
|
*/
|
|
359
386
|
async reset() {
|
|
387
|
+
this.clearSelectedDisplay();
|
|
360
388
|
this.value = '';
|
|
361
389
|
this.selectedOptions = [];
|
|
362
390
|
this.searchText = '';
|
|
@@ -473,6 +501,11 @@ export class Q2Search {
|
|
|
473
501
|
return count > 1 ? `+${count - 1}` : null;
|
|
474
502
|
return `${count}`;
|
|
475
503
|
}
|
|
504
|
+
get firstSelectedOptionElement() {
|
|
505
|
+
var _a, _b;
|
|
506
|
+
const v = this.multiple ? (_a = this.selectedOptions) === null || _a === void 0 ? void 0 : _a[0] : this.value;
|
|
507
|
+
return v ? (_b = this.optionElements.find(o => o.value === v)) !== null && _b !== void 0 ? _b : null : null;
|
|
508
|
+
}
|
|
476
509
|
get innerInputContainer() {
|
|
477
510
|
var _a, _b, _c;
|
|
478
511
|
return (_c = (_b = (_a = this.inputField) === null || _a === void 0 ? void 0 : _a.shadowRoot) === null || _b === void 0 ? void 0 : _b.querySelector('.input-container')) !== null && _c !== void 0 ? _c : null;
|
|
@@ -509,6 +542,9 @@ export class Q2Search {
|
|
|
509
542
|
const rowHeight = Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
510
543
|
return this.minRows * rowHeight;
|
|
511
544
|
}
|
|
545
|
+
get selectedDisplaySlot() {
|
|
546
|
+
return this.hostElement.querySelector('[slot="_selected-display"]');
|
|
547
|
+
}
|
|
512
548
|
get visibleOptionElements() {
|
|
513
549
|
return this.optionElements.filter(opt => !opt.hidden);
|
|
514
550
|
}
|
|
@@ -542,12 +578,50 @@ export class Q2Search {
|
|
|
542
578
|
const { multilineOptions } = this;
|
|
543
579
|
this.optionElements.forEach(option => (option.multiline = multilineOptions));
|
|
544
580
|
}
|
|
581
|
+
checkSelectedDisplay() {
|
|
582
|
+
var _a;
|
|
583
|
+
const { multilineOptions, isShowingSelectionDisplay, value, multiple, selectedOptions, firstSelectedOptionElement, } = this;
|
|
584
|
+
const hasNoValue = multiple ? !(selectedOptions === null || selectedOptions === void 0 ? void 0 : selectedOptions.length) : !value;
|
|
585
|
+
if (!multilineOptions || !isShowingSelectionDisplay || hasNoValue)
|
|
586
|
+
return this.clearSelectedDisplay();
|
|
587
|
+
if (!firstSelectedOptionElement || firstSelectedOptionElement.display)
|
|
588
|
+
return this.clearSelectedDisplay();
|
|
589
|
+
const child = firstSelectedOptionElement.firstElementChild;
|
|
590
|
+
if (!child)
|
|
591
|
+
return this.clearSelectedDisplay();
|
|
592
|
+
const selectionClone = child.cloneNode(true);
|
|
593
|
+
selectionClone.querySelectorAll('[hide-on-select]').forEach(el => el.remove());
|
|
594
|
+
let namedSlot = this.selectedDisplaySlot;
|
|
595
|
+
if (namedSlot) {
|
|
596
|
+
if (((_a = namedSlot.firstElementChild) === null || _a === void 0 ? void 0 : _a.outerHTML) !== selectionClone.outerHTML) {
|
|
597
|
+
namedSlot.replaceChildren(selectionClone);
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
else {
|
|
601
|
+
namedSlot = document.createElement('div');
|
|
602
|
+
namedSlot.slot = '_selected-display';
|
|
603
|
+
// Prevent the non-focusable overlay from blurring the hidden input when clicked.
|
|
604
|
+
// Same pattern used by q2-input's clear button (onMouseDown preventDefault).
|
|
605
|
+
namedSlot.addEventListener('mousedown', this.onSelectedDisplayMousedown);
|
|
606
|
+
namedSlot.appendChild(selectionClone);
|
|
607
|
+
this.hostElement.appendChild(namedSlot);
|
|
608
|
+
}
|
|
609
|
+
return namedSlot;
|
|
610
|
+
}
|
|
545
611
|
checkSelectedOptions() {
|
|
546
612
|
const { multiple, selectedOptions, value } = this;
|
|
547
613
|
this.optionElements.forEach(option => {
|
|
548
614
|
option.selected = multiple ? selectedOptions.includes(option.value) : option.value === value;
|
|
549
615
|
});
|
|
550
616
|
}
|
|
617
|
+
clearSelectedDisplay() {
|
|
618
|
+
const slot = this.selectedDisplaySlot;
|
|
619
|
+
if (slot) {
|
|
620
|
+
slot.removeEventListener('mousedown', this.onSelectedDisplayMousedown);
|
|
621
|
+
slot.remove();
|
|
622
|
+
}
|
|
623
|
+
return null;
|
|
624
|
+
}
|
|
551
625
|
closeDropdown() {
|
|
552
626
|
if (!this.open)
|
|
553
627
|
return;
|
|
@@ -574,8 +648,16 @@ export class Q2Search {
|
|
|
574
648
|
this.open = true;
|
|
575
649
|
this.tctOpen.emit();
|
|
576
650
|
}
|
|
651
|
+
optionDisplayText(option, fallback = '') {
|
|
652
|
+
var _a, _b;
|
|
653
|
+
if (option === null || option === void 0 ? void 0 : option.display)
|
|
654
|
+
return loc(option.display);
|
|
655
|
+
if (this.multilineOptions)
|
|
656
|
+
return '';
|
|
657
|
+
return (_b = (_a = option === null || option === void 0 ? void 0 : option.textContent) === null || _a === void 0 ? void 0 : _a.trim()) !== null && _b !== void 0 ? _b : fallback;
|
|
658
|
+
}
|
|
577
659
|
revertToSelectedDisplay() {
|
|
578
|
-
var _a, _b, _c
|
|
660
|
+
var _a, _b, _c;
|
|
579
661
|
if (this.multiple) {
|
|
580
662
|
// Preserve an in-progress query — user blurred without selecting and may resume.
|
|
581
663
|
if (this.searchText)
|
|
@@ -589,7 +671,7 @@ export class Q2Search {
|
|
|
589
671
|
// re-populated yet) — leave the query alone rather than blanking it.
|
|
590
672
|
if (!selected)
|
|
591
673
|
return;
|
|
592
|
-
const display =
|
|
674
|
+
const display = this.optionDisplayText(selected);
|
|
593
675
|
this.searchText = display;
|
|
594
676
|
this.isShowingSelectionDisplay = true;
|
|
595
677
|
return;
|
|
@@ -602,10 +684,16 @@ export class Q2Search {
|
|
|
602
684
|
// Same guard: don't clobber an in-progress query when the matching option isn't in the DOM.
|
|
603
685
|
if (!selected)
|
|
604
686
|
return;
|
|
605
|
-
const display = selected.display
|
|
687
|
+
const display = selected.display
|
|
688
|
+
? loc(selected.display)
|
|
689
|
+
: this.multilineOptions
|
|
690
|
+
? ''
|
|
691
|
+
: (_c = (_b = selected.textContent) === null || _b === void 0 ? void 0 : _b.trim()) !== null && _c !== void 0 ? _c : '';
|
|
606
692
|
this.isShowingSelectionDisplay = true;
|
|
607
|
-
if (this.searchText === display)
|
|
693
|
+
if (this.searchText === display) {
|
|
694
|
+
this.checkSelectedDisplay();
|
|
608
695
|
return;
|
|
696
|
+
}
|
|
609
697
|
this.searchText = display;
|
|
610
698
|
}
|
|
611
699
|
setCustomLabel() {
|
|
@@ -640,6 +728,11 @@ export class Q2Search {
|
|
|
640
728
|
}
|
|
641
729
|
// #endregion
|
|
642
730
|
// #region Render Methods
|
|
731
|
+
renderCustomDisplay() {
|
|
732
|
+
if (!this.checkSelectedDisplay())
|
|
733
|
+
return null;
|
|
734
|
+
return (h("slot", { name: "_selected-display", slot: "custom-display" }));
|
|
735
|
+
}
|
|
643
736
|
renderEmpty() {
|
|
644
737
|
if (this.hasEmptySlot) {
|
|
645
738
|
return h("slot", { name: "empty" });
|
|
@@ -669,9 +762,9 @@ export class Q2Search {
|
|
|
669
762
|
return (h("q2-popover", { ref: el => (this.popoverElement = el), controlElement: (_a = this.innerInputContainer) !== null && _a !== void 0 ? _a : undefined, open: this.open, maxHeight: this.popoverMaxHeight, minHeight: this.popoverMinHeight, align: useBlock ? undefined : this.popoverAlignment, block: useBlock }, h("div", { class: "popover-content", "data-loading": this.loading ? 'true' : 'false', "aria-busy": this.loading ? 'true' : null }, h("div", { class: "popover-top-container", hidden: !this.hasPopoverTop && !(this.multiple && this.showSelectedToggle), tabindex: "-1" }, h("slot", { name: "popover-top" }), !this.loading && this.renderMultiSelectHeader()), h("q2-option-list", { ref: el => (this.optionList = el), type: "listbox", id: this.optionListId, label: loc(this.listLabel), multiple: this.multiple, selectedOptions: this.structuredSelectedOptions, showSelected: this.showSelected, customSearch: true, hidden: this.loading, onChange: (e) => e.stopPropagation(), onTctChange: this.onOptionListChange }, h("slot", null)), showEmpty && this.renderEmpty(), h("div", { class: "popover-bottom-container", hidden: !this.hasPopoverBottom, tabindex: "-1" }, h("slot", { name: "popover-bottom" })), this.loading && (h("div", { class: "loading-overlay", "aria-hidden": "true" }, h("q2-loading", { type: "spinner" }))))));
|
|
670
763
|
}
|
|
671
764
|
render() {
|
|
672
|
-
return (h(Fragment, { key: '
|
|
765
|
+
return (h(Fragment, { key: '0686476c153375c6c3cca61cdeaf1267c5ca6b20' }, h("div", { key: 'f5ed583b8da30b2222dd4a466a37e1c10b589fa7', "aria-live": "polite", "aria-atomic": "true", role: "status", class: "sr" }, this.statusMessage), h("click-elsewhere", { key: 'f1172a06706ea799f6020d21610004450e051d9a', class: this.wrapperClasses, role: "presentation", onChange: this.onClickElsewhere }, h("q2-input", { key: '75675f105bd09279650e6aae6b869e0f3f99c270', ref: el => (this.inputField = el), class: "q2-search-input", label: (this.label && loc(this.label)) || '', value: this.searchText, iconLeft: "search", clearable: this.clearable && !this.loading && !!this.searchText, disabled: this.disabled, optional: this.optional, readonly: !!this.readonly, placeholder: this.placeholder ? loc(this.placeholder) : undefined, hideLabel: this.hideLabel, errors: (Array.isArray(this.errors) && this.errors.length > 0 && this.errors.map(e => loc(e))) ||
|
|
673
766
|
(this.invalid && ['tecton.element.search.invalid']) ||
|
|
674
|
-
[], ariaExpanded: this.isInputOnlyMode ? undefined : `${this.open}`, ariaControls: this.isInputOnlyMode ? undefined : this.optionListId, ariaHaspopup: this.isInputOnlyMode ? undefined : 'listbox', hideMessages: true, _role: this.isInputOnlyMode ? undefined : 'combobox', onTctInput: this.inputInputHandler, onInput: (e) => e.stopImmediatePropagation(), onChange: (e) => e.stopPropagation(), onTctChange: (e) => e.stopPropagation(), badgeValue: this.badgeValue }), this.renderOptionsDropdown())));
|
|
767
|
+
[], ariaExpanded: this.isInputOnlyMode ? undefined : `${this.open}`, ariaControls: this.isInputOnlyMode ? undefined : this.optionListId, ariaHaspopup: this.isInputOnlyMode ? undefined : 'listbox', hideMessages: true, _role: this.isInputOnlyMode ? undefined : 'combobox', onTctInput: this.inputInputHandler, onInput: (e) => e.stopImmediatePropagation(), onChange: (e) => e.stopPropagation(), onTctChange: (e) => e.stopPropagation(), badgeValue: this.badgeValue }, this.renderCustomDisplay()), this.renderOptionsDropdown())));
|
|
675
768
|
}
|
|
676
769
|
static get is() { return "q2-search"; }
|
|
677
770
|
static get encapsulation() { return "shadow"; }
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { expect } from "@playwright/test";
|
|
2
|
+
import { test } from "@stencil/playwright";
|
|
3
|
+
import { setupPage, THEMES } from "../../../utils/test/vr-helpers";
|
|
4
|
+
const OPTIONS = `
|
|
5
|
+
<q2-option value="1" display="Apothecary"></q2-option>
|
|
6
|
+
<q2-option value="2" display="Borant"></q2-option>
|
|
7
|
+
<q2-option value="3" display="Valtay"></q2-option>
|
|
8
|
+
`;
|
|
9
|
+
const ERRORS = ['This field is required.', 'The value entered is invalid.'];
|
|
10
|
+
const VARIANTS = [
|
|
11
|
+
{
|
|
12
|
+
name: 'default',
|
|
13
|
+
html: '<q2-search label="Search" placeholder="Type to search"></q2-search>',
|
|
14
|
+
states: ['resting', 'focus'],
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
name: 'clearable-with-value',
|
|
18
|
+
html: `<q2-search label="Search" clearable value="1">${OPTIONS}</q2-search>`,
|
|
19
|
+
states: ['resting'],
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
name: 'optional',
|
|
23
|
+
html: '<q2-search label="Search" optional placeholder="Type to search"></q2-search>',
|
|
24
|
+
states: ['resting'],
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
name: 'readonly',
|
|
28
|
+
html: `<q2-search label="Search" readonly value="1">${OPTIONS}</q2-search>`,
|
|
29
|
+
states: ['resting'],
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
name: 'disabled',
|
|
33
|
+
html: '<q2-search label="Search" disabled placeholder="Type to search"></q2-search>',
|
|
34
|
+
states: ['resting'],
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: 'errored',
|
|
38
|
+
html: '<q2-search label="Search" placeholder="Type to search"></q2-search>',
|
|
39
|
+
states: ['resting'],
|
|
40
|
+
setup: 'errors',
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
name: 'expanded',
|
|
44
|
+
html: `<q2-search label="Search">${OPTIONS}</q2-search>`,
|
|
45
|
+
states: ['expanded', 'expanded-option-hover', 'expanded-option-focus'],
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
name: 'loading',
|
|
49
|
+
html: '<q2-search label="Search" loading placeholder="Type to search"></q2-search>',
|
|
50
|
+
states: ['expanded'],
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: 'no-results',
|
|
54
|
+
html: '<q2-search label="Search"></q2-search>',
|
|
55
|
+
states: ['expanded'],
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
name: 'multiple',
|
|
59
|
+
html: `<q2-search label="Search" multiple filter>${OPTIONS}</q2-search>`,
|
|
60
|
+
states: ['expanded', 'expanded-option-hover', 'expanded-option-focus'],
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
name: 'multiple-show-selected-toggle',
|
|
64
|
+
html: `<q2-search label="Search" multiple filter show-selected-toggle>${OPTIONS}</q2-search>`,
|
|
65
|
+
states: ['expanded'],
|
|
66
|
+
setup: 'multiple-selected',
|
|
67
|
+
},
|
|
68
|
+
];
|
|
69
|
+
const applySetup = async (page, setup) => {
|
|
70
|
+
if (!setup)
|
|
71
|
+
return;
|
|
72
|
+
await page.evaluate(({ setup, errors }) => {
|
|
73
|
+
const el = document.querySelector('q2-search');
|
|
74
|
+
if (setup === 'errors')
|
|
75
|
+
el.errors = errors;
|
|
76
|
+
if (setup === 'multiple-selected')
|
|
77
|
+
el.selectedOptions = ['1'];
|
|
78
|
+
}, { setup, errors: ERRORS });
|
|
79
|
+
};
|
|
80
|
+
const openSearch = async (page, hasOptions) => {
|
|
81
|
+
await page.evaluate(() => {
|
|
82
|
+
const el = document.querySelector('q2-search');
|
|
83
|
+
return el.openPopover();
|
|
84
|
+
});
|
|
85
|
+
if (hasOptions) {
|
|
86
|
+
await page.locator('q2-option').first().waitFor({ state: 'visible' });
|
|
87
|
+
}
|
|
88
|
+
// Wait for the popover open transition (box-shadow, opacity) to fully settle.
|
|
89
|
+
await page.waitForTimeout(300);
|
|
90
|
+
};
|
|
91
|
+
const setup = (page, variant, theme) => setupPage(page, variant.html, { theme, setupLoc: true }).then(() => applySetup(page, variant.setup));
|
|
92
|
+
const restingCase = (variant, theme) => {
|
|
93
|
+
test(`q2-search--${variant.name}--resting — ${theme}`, async ({ page }) => {
|
|
94
|
+
await setup(page, variant, theme);
|
|
95
|
+
await expect(page).toHaveScreenshot(`q2-search--${variant.name}--resting--${theme}.png`);
|
|
96
|
+
});
|
|
97
|
+
};
|
|
98
|
+
const focusCase = (variant, theme) => {
|
|
99
|
+
test(`q2-search--${variant.name}--focus — ${theme}`, async ({ page }) => {
|
|
100
|
+
await setup(page, variant, theme);
|
|
101
|
+
await page.keyboard.press('Tab');
|
|
102
|
+
await expect(page).toHaveScreenshot(`q2-search--${variant.name}--focus--${theme}.png`);
|
|
103
|
+
});
|
|
104
|
+
};
|
|
105
|
+
const expandedCase = (variant, theme) => {
|
|
106
|
+
const hasOptions = !variant.name.includes('loading') && !variant.name.includes('no-results');
|
|
107
|
+
test(`q2-search--${variant.name}--expanded — ${theme}`, async ({ page }) => {
|
|
108
|
+
await setup(page, variant, theme);
|
|
109
|
+
await openSearch(page, hasOptions);
|
|
110
|
+
await expect(page).toHaveScreenshot(`q2-search--${variant.name}--expanded--${theme}.png`);
|
|
111
|
+
});
|
|
112
|
+
};
|
|
113
|
+
const expandedOptionHoverCase = (variant, theme) => {
|
|
114
|
+
test(`q2-search--${variant.name}--expanded-option-hover — ${theme}`, async ({ page }) => {
|
|
115
|
+
await setup(page, variant, theme);
|
|
116
|
+
await openSearch(page, true);
|
|
117
|
+
await page.locator('q2-option[value="1"]').hover();
|
|
118
|
+
await expect(page).toHaveScreenshot(`q2-search--${variant.name}--expanded-option-hover--${theme}.png`);
|
|
119
|
+
});
|
|
120
|
+
};
|
|
121
|
+
// ArrowDown after open moves focus to the first option, triggering :focus-visible.
|
|
122
|
+
const expandedOptionFocusCase = (variant, theme) => {
|
|
123
|
+
test(`q2-search--${variant.name}--expanded-option-focus — ${theme}`, async ({ page }) => {
|
|
124
|
+
await setup(page, variant, theme);
|
|
125
|
+
await openSearch(page, true);
|
|
126
|
+
await page.keyboard.press('ArrowDown');
|
|
127
|
+
await expect(page).toHaveScreenshot(`q2-search--${variant.name}--expanded-option-focus--${theme}.png`);
|
|
128
|
+
});
|
|
129
|
+
};
|
|
130
|
+
const CASE_MAP = {
|
|
131
|
+
resting: restingCase,
|
|
132
|
+
focus: focusCase,
|
|
133
|
+
expanded: expandedCase,
|
|
134
|
+
'expanded-option-hover': expandedOptionHoverCase,
|
|
135
|
+
'expanded-option-focus': expandedOptionFocusCase,
|
|
136
|
+
};
|
|
137
|
+
test.describe('q2-search — variants × themes', () => {
|
|
138
|
+
for (const variant of VARIANTS) {
|
|
139
|
+
for (const theme of THEMES) {
|
|
140
|
+
for (const state of variant.states) {
|
|
141
|
+
CASE_MAP[state](variant, theme);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
});
|
|
@@ -94,7 +94,7 @@ button {
|
|
|
94
94
|
:host {
|
|
95
95
|
display: block;
|
|
96
96
|
background: var(--tct-section-background, var(--tct-section-background-color, var(--t-section-background-color, var(--tct-section-bg, var(--t-section-bg, var(--app-white, #ffffff))))));
|
|
97
|
-
color: var(--tct-section-font-color, var(--t-section-font-color,
|
|
97
|
+
color: var(--tct-section-font-color, var(--t-section-font-color, inherit));
|
|
98
98
|
border-radius: var(--tct-section-border-radius, var(--t-section-border-radius, var(--app-border-radius-1, 4px)));
|
|
99
99
|
margin: var(--tct-section-margin, var(--t-section-margin, var(--app-scale-3x, 15px)));
|
|
100
100
|
border-width: var(--tct-section-border-width, 0);
|
|
@@ -128,8 +128,8 @@ button {
|
|
|
128
128
|
* @prop --tct-select-margin: (<length-percentage>+) Controls the outer margin of the select host.
|
|
129
129
|
* @prop --tct-select-margin-top: (<length-percentage>) Controls the top margin of the select host when --tct-select-margin is not set.
|
|
130
130
|
* @prop --tct-select-margin-bottom: (<length-percentage>) Controls the bottom margin of the select host when --tct-select-margin is not set.
|
|
131
|
-
* @prop --tct-select-input-min-height?: (<length-percentage>) Controls the optional minimum height of the select input.
|
|
132
|
-
* @prop --tct-select-input-max-height?: (<length-percentage>) Controls the optional maximum height of the select input.
|
|
131
|
+
* @prop --tct-select-input-min-height?: (<length-percentage>) Controls the optional minimum height of the select input. Use this to control the height of the select in the empty state, especially when using multiline-options with tall content.
|
|
132
|
+
* @prop --tct-select-input-max-height?: (<length-percentage>) Controls the optional maximum height of the select input. Use this to constrain the height when displaying multiline selected content.
|
|
133
133
|
* @prop --tct-select-multi-select-option-background?: (<color>) Controls the optional background color of multi-select option chips in their default state.
|
|
134
134
|
* @prop --tct-select-multi-select-option-color?: (<color>) Controls the optional text color of multi-select option chips in their default state.
|
|
135
135
|
* @prop --tct-select-multi-select-option-active-background: (<color>) Controls the background color of multi-select option chips when active (checked).
|
|
@@ -161,6 +161,8 @@ button {
|
|
|
161
161
|
::slotted([slot=_selected-display]) {
|
|
162
162
|
width: 100%;
|
|
163
163
|
min-height: var(--comp-selected-display-height, 44px);
|
|
164
|
+
padding-top: var(--tct-select-selected-display-padding, var(--app-scale-2x, 10px));
|
|
165
|
+
padding-bottom: var(--tct-select-selected-display-padding, var(--app-scale-2x, 10px));
|
|
164
166
|
}
|
|
165
167
|
|
|
166
168
|
.custom-display-content {
|
|
@@ -82,6 +82,8 @@ export class Q2Select {
|
|
|
82
82
|
* This property is only relevant for `multiple` (i.e., multi-select) implementations.
|
|
83
83
|
*/
|
|
84
84
|
this.selectedOptions = [];
|
|
85
|
+
/** Determines whether to show a success state. The error state takes precedence when both are set. */
|
|
86
|
+
this.valid = false;
|
|
85
87
|
this.addTouchEventListeners = () => {
|
|
86
88
|
if (!isMobile() || !this.popoverElement)
|
|
87
89
|
return;
|
|
@@ -271,6 +273,22 @@ export class Q2Select {
|
|
|
271
273
|
return;
|
|
272
274
|
this.open = open;
|
|
273
275
|
};
|
|
276
|
+
this.onSelectedDisplayClick = (event) => {
|
|
277
|
+
// Stop click from bubbling to q2-input's onClick (which would toggle the dropdown)
|
|
278
|
+
event.stopPropagation();
|
|
279
|
+
if (this.open) {
|
|
280
|
+
this.focusInput();
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
this.prioritizeSearch = this.searchable;
|
|
284
|
+
this.clearSelectedDisplay();
|
|
285
|
+
this.openDropdownWithoutActiveElement();
|
|
286
|
+
this.focusInput();
|
|
287
|
+
};
|
|
288
|
+
this.onSelectedDisplayMousedown = (event) => {
|
|
289
|
+
// Prevent focus shift away from the hidden input
|
|
290
|
+
event.preventDefault();
|
|
291
|
+
};
|
|
274
292
|
this.removeTouchEventListeners = () => {
|
|
275
293
|
if (!isMobile() || !this.popoverElement)
|
|
276
294
|
return;
|
|
@@ -495,6 +513,8 @@ export class Q2Select {
|
|
|
495
513
|
}
|
|
496
514
|
else {
|
|
497
515
|
this.removeTouchEventListeners();
|
|
516
|
+
// Reset prioritizeSearch when dropdown closes to ensure selected display can be restored
|
|
517
|
+
this.prioritizeSearch = false;
|
|
498
518
|
}
|
|
499
519
|
this.scheduledAfterRender.push(async () => {
|
|
500
520
|
await waitForNextPaint();
|
|
@@ -657,10 +677,16 @@ export class Q2Select {
|
|
|
657
677
|
if (namedSlot.firstElementChild.outerHTML !== selectionClone.outerHTML) {
|
|
658
678
|
namedSlot.replaceChild(selectionClone, namedSlot.firstElementChild);
|
|
659
679
|
}
|
|
680
|
+
namedSlot.removeEventListener('mousedown', this.onSelectedDisplayMousedown);
|
|
681
|
+
namedSlot.addEventListener('mousedown', this.onSelectedDisplayMousedown);
|
|
682
|
+
namedSlot.removeEventListener('click', this.onSelectedDisplayClick);
|
|
683
|
+
namedSlot.addEventListener('click', this.onSelectedDisplayClick);
|
|
660
684
|
}
|
|
661
685
|
else {
|
|
662
686
|
namedSlot = document.createElement('div');
|
|
663
687
|
namedSlot.slot = '_selected-display';
|
|
688
|
+
namedSlot.addEventListener('mousedown', this.onSelectedDisplayMousedown);
|
|
689
|
+
namedSlot.addEventListener('click', this.onSelectedDisplayClick);
|
|
664
690
|
namedSlot.appendChild(selectionClone);
|
|
665
691
|
this.hostElement.appendChild(namedSlot);
|
|
666
692
|
}
|
|
@@ -690,8 +716,12 @@ export class Q2Select {
|
|
|
690
716
|
mirrorEmit(this, ['input', 'tctInput'], { query: '' });
|
|
691
717
|
}
|
|
692
718
|
clearSelectedDisplay() {
|
|
693
|
-
|
|
694
|
-
(
|
|
719
|
+
const slot = this.selectedDisplaySlot;
|
|
720
|
+
if (slot) {
|
|
721
|
+
slot.removeEventListener('mousedown', this.onSelectedDisplayMousedown);
|
|
722
|
+
slot.removeEventListener('click', this.onSelectedDisplayClick);
|
|
723
|
+
slot.remove();
|
|
724
|
+
}
|
|
695
725
|
}
|
|
696
726
|
clearValue() {
|
|
697
727
|
const { multiple } = this;
|
|
@@ -786,7 +816,7 @@ export class Q2Select {
|
|
|
786
816
|
this.errors.length > 0 &&
|
|
787
817
|
this.errors.map(error => loc(error))) ||
|
|
788
818
|
(this.invalid && ['tecton.element.select.invalid']) ||
|
|
789
|
-
[], disabled: this.disabled, optional: this.optional, readonly: !!this.readonly, placeholder: this.placeholder || undefined, hideLabel: this.hideLabel, ariaExpanded: `${this.open}`, ariaControls: "option-list", ariaHaspopup: "listbox", "test-id": "toggleDropdown", "hide-messages": true, iconRight: "chevron-down", onClick: this.inputClickHandler, onInput: e => e.stopImmediatePropagation(), onTctInput: this.inputInputHandler, onKeyDown: this.inputKeydownHandler, onFocus: this.inputFocusHandler, onBlur: this.inputBlurHandler, onChange: e => e.stopPropagation(), onTctChange: this.inputChangeHandler, badgeValue: this.badgeValue, badgeTheme: this.inputFocused ? 'primary' : undefined, _role: "combobox", _preventEntry: !this.searchable }, this.renderCustomDisplay()), h("div", { class: "custom-display-content", hidden: !this.hasCustomDisplay || !!this.searchText, onClick: this.onCustomDisplayClick }, h("slot", { name: "q2-select-display" })), this.renderOptionsDropdown()));
|
|
819
|
+
[], disabled: this.disabled, optional: this.optional, readonly: !!this.readonly, placeholder: this.placeholder || undefined, hideLabel: this.hideLabel, valid: this.valid, ariaExpanded: `${this.open}`, ariaControls: "option-list", ariaHaspopup: "listbox", "test-id": "toggleDropdown", "hide-messages": true, iconRight: "chevron-down", onClick: this.inputClickHandler, onInput: e => e.stopImmediatePropagation(), onTctInput: this.inputInputHandler, onKeyDown: this.inputKeydownHandler, onFocus: this.inputFocusHandler, onBlur: this.inputBlurHandler, onChange: e => e.stopPropagation(), onTctChange: this.inputChangeHandler, badgeValue: this.badgeValue, badgeTheme: this.inputFocused ? 'primary' : undefined, _role: "combobox", _preventEntry: !this.searchable }, this.renderCustomDisplay()), h("div", { class: "custom-display-content", hidden: !this.hasCustomDisplay || !!this.searchText, onClick: this.onCustomDisplayClick }, h("slot", { name: "q2-select-display" })), this.renderOptionsDropdown()));
|
|
790
820
|
}
|
|
791
821
|
renderVisibilityToggle() {
|
|
792
822
|
var _a, _b;
|
|
@@ -797,7 +827,7 @@ export class Q2Select {
|
|
|
797
827
|
]), checked: showSelected, "test-id": "selectedOptionsButton", onClick: this.showSelectedOptions, onKeyDown: this.visibilityToggleKeyDown }), h("label", { htmlFor: "selected" }, loc('tecton.element.select.multiHeader.selected', [selectedOptionsCount]))))));
|
|
798
828
|
}
|
|
799
829
|
render() {
|
|
800
|
-
return (h("click-elsewhere", { key: '
|
|
830
|
+
return (h("click-elsewhere", { key: 'a08e10cf8bd4e2d3f210d36003417f2a1dec4b21', class: this.wrapperClasses, role: "presentation", onChange: this.clickedElsewhere }, this.renderSelectField()));
|
|
801
831
|
}
|
|
802
832
|
static get is() { return "q2-select"; }
|
|
803
833
|
static get encapsulation() { return "shadow"; }
|
|
@@ -1227,6 +1257,26 @@ export class Q2Select {
|
|
|
1227
1257
|
"setter": false,
|
|
1228
1258
|
"defaultValue": "[]"
|
|
1229
1259
|
},
|
|
1260
|
+
"valid": {
|
|
1261
|
+
"type": "boolean",
|
|
1262
|
+
"mutable": false,
|
|
1263
|
+
"complexType": {
|
|
1264
|
+
"original": "boolean",
|
|
1265
|
+
"resolved": "boolean",
|
|
1266
|
+
"references": {}
|
|
1267
|
+
},
|
|
1268
|
+
"required": false,
|
|
1269
|
+
"optional": false,
|
|
1270
|
+
"docs": {
|
|
1271
|
+
"tags": [],
|
|
1272
|
+
"text": "Determines whether to show a success state. The error state takes precedence when both are set."
|
|
1273
|
+
},
|
|
1274
|
+
"getter": false,
|
|
1275
|
+
"setter": false,
|
|
1276
|
+
"reflect": true,
|
|
1277
|
+
"attribute": "valid",
|
|
1278
|
+
"defaultValue": "false"
|
|
1279
|
+
},
|
|
1230
1280
|
"value": {
|
|
1231
1281
|
"type": "string",
|
|
1232
1282
|
"mutable": true,
|
|
@@ -44,6 +44,11 @@ const VARIANTS = [
|
|
|
44
44
|
states: ['resting'],
|
|
45
45
|
setup: 'errors',
|
|
46
46
|
},
|
|
47
|
+
{
|
|
48
|
+
name: 'valid',
|
|
49
|
+
html: `<q2-select label="My select" placeholder="Select an option" valid value="2">${OPTIONS}</q2-select>`,
|
|
50
|
+
states: ['resting'],
|
|
51
|
+
},
|
|
47
52
|
];
|
|
48
53
|
const applySelectSetup = async (page, setup) => {
|
|
49
54
|
if (!setup)
|
|
@@ -275,7 +275,7 @@ li {
|
|
|
275
275
|
}
|
|
276
276
|
|
|
277
277
|
.step-label {
|
|
278
|
-
color: var(--tct-stepper-label-color, var(--tct-stepper-title-color, var(--t-stepper-title-color,
|
|
278
|
+
color: var(--tct-stepper-label-color, var(--tct-stepper-title-color, var(--t-stepper-title-color, inherit)));
|
|
279
279
|
font-size: var(--tct-stepper-label-font-size, var(--tct-stepper-title-font-size, var(--t-stepper-title-font-size, var(--app-font-size-small, 12px))));
|
|
280
280
|
line-height: var(--tct-stepper-label-line-height, 1.5em);
|
|
281
281
|
text-overflow: ellipsis;
|
|
@@ -290,7 +290,7 @@ li {
|
|
|
290
290
|
}
|
|
291
291
|
|
|
292
292
|
.step-description {
|
|
293
|
-
color: var(--tct-stepper-description-color, var(--t-stepper-description-color,
|
|
293
|
+
color: var(--tct-stepper-description-color, var(--t-stepper-description-color, inherit));
|
|
294
294
|
font-size: var(--tct-stepper-description-font-size, var(--t-stepper-description-font-size, var(--app-font-size-small, 12px)));
|
|
295
295
|
text-overflow: ellipsis;
|
|
296
296
|
overflow: hidden;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { h, Fragment, } from "@stencil/core";
|
|
2
2
|
import { loc, overrideFocus, isEventFromElement, createGuid } from "../../utils/index";
|
|
3
3
|
import mirrorEmit from "../../utils/mirror-emit";
|
|
4
|
+
import sanitizeHTMLString from "../../utils/sanitize-html-string";
|
|
4
5
|
/**
|
|
5
6
|
* @name Stepper
|
|
6
7
|
* @category Display
|
|
@@ -273,14 +274,14 @@ export class Q2Stepper {
|
|
|
273
274
|
if (isPaneDisabled)
|
|
274
275
|
stepClasses.push('pane-disabled');
|
|
275
276
|
const disabled = isLocked || stepNumber > lastEnabledStep;
|
|
276
|
-
return (h("li", { role: "presentation" }, h("button", { class: stepClasses.join(' '), type: "button", "aria-labelledby": labelId, "aria-describedBy": descriptionId, "aria-label": btnLabel, "aria-selected": `${isCurrentStep}`, "aria-disabled": disabled ? 'true' : undefined, role: "tab", tabIndex: isCurrentStep ? 0 : -1, onKeyDown: ev => this.onStepKeyDown(ev, stepNumber), onClick: ev => !isPaneDisabled && !disabled && this.onStepClick(ev, stepNumber) }, h(Fragment, null, statusIcon ? (h("div", { class: "step-icon" }, h("q2-icon", { type: statusIcon }))) : (h("div", { class: "step-bubble" }, stepNumber)), labelId && (h("div", { class: "step-label", id: labelId, innerHTML: label })), labelId && descriptionId && (h("div", { class: "step-description", id: descriptionId, innerHTML: description })))), stepIndex ? h("div", { class: "step-divider" }) : ''));
|
|
277
|
+
return (h("li", { role: "presentation" }, h("button", { class: stepClasses.join(' '), type: "button", "aria-labelledby": labelId, "aria-describedBy": descriptionId, "aria-label": btnLabel, "aria-selected": `${isCurrentStep}`, "aria-disabled": disabled ? 'true' : undefined, role: "tab", tabIndex: isCurrentStep ? 0 : -1, onKeyDown: ev => this.onStepKeyDown(ev, stepNumber), onClick: ev => !isPaneDisabled && !disabled && this.onStepClick(ev, stepNumber) }, h(Fragment, null, statusIcon ? (h("div", { class: "step-icon" }, h("q2-icon", { type: statusIcon }))) : (h("div", { class: "step-bubble" }, stepNumber)), labelId && (h("div", { class: "step-label", id: labelId, innerHTML: sanitizeHTMLString(label) })), labelId && descriptionId && (h("div", { class: "step-description", id: descriptionId, innerHTML: sanitizeHTMLString(description) })))), stepIndex ? h("div", { class: "step-divider" }) : ''));
|
|
277
278
|
}
|
|
278
279
|
render() {
|
|
279
280
|
const { stepCount, scrollEnabled, showScrollLeft, showScrollRight } = this;
|
|
280
281
|
const containerClasses = ['step-container'];
|
|
281
282
|
if (scrollEnabled)
|
|
282
283
|
containerClasses.push('has-scroll');
|
|
283
|
-
return (h(Fragment, { key: '
|
|
284
|
+
return (h(Fragment, { key: 'c1e21a36e0b2f684f4520b0f75f78affd73359bd' }, h("div", { key: '3791e857d27aa3fea928f663268f21270d499023', class: containerClasses.join(' ') }, scrollEnabled && (h(Fragment, { key: '19b689b2b56f52099f22f859264e33e16fd918bf' }, h("div", { key: '5b1b1e00034fa009c555924c2067fed6369740cb', class: "gradient-left", hidden: !showScrollLeft }), h("div", { key: 'b5de1b413f6c8ce006207926f26ae845594228eb', class: "gradient-right", hidden: !showScrollRight }), h("q2-btn", { key: '832a97c5619cadb1167f6e1e7ecd94ab4f5f3cb1', class: "btn-left", hideLabel: true, hidden: !this.showScrollLeft, label: loc('tecton.element.stepper.scrollLeft'), onTctClick: () => this.onScrollBtnClick('left') }, h("q2-icon", { key: '3e53b2b2f19bbba59a37016b9cdf1a302b030b63', type: "chevron-left" })), h("q2-btn", { key: 'ffacbb0d2f9c15a503221a2dbc4662ba6f3c3272', class: "btn-right", hideLabel: true, hidden: !this.showScrollRight, label: loc('tecton.element.stepper.scrollRight'), onTctClick: () => this.onScrollBtnClick('right') }, h("q2-icon", { key: '2c60dc5392c9c9eec99dd24b229bbd1fa5e9587f', type: "chevron-right" })))), h("ul", { key: '25806a72f9f0cda2e032a81dbaac9f808be385c9', onScroll: this.checkScrollState, ref: el => (this.listElement = el), role: "tablist" }, stepCount > 0 && [...Array(stepCount).keys()].map(stepIndex => this.renderStepBtn(stepIndex)))), h("div", { key: '622b3ed56e3f66adc33bf197b7874a7b9bf8667f', role: "list" }, h("slot", { key: '73c4321743596227054e317c271bcc044179363b', onSlotchange: () => this.onSlotChange() }))));
|
|
284
285
|
}
|
|
285
286
|
static get is() { return "q2-stepper"; }
|
|
286
287
|
static get encapsulation() { return "shadow"; }
|