@nyaruka/temba-components 0.113.0 → 0.114.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/CHANGELOG.md +21 -2
- package/demo/index.html +1 -1
- package/dist/temba-components.js +793 -966
- package/dist/temba-components.js.map +1 -1
- package/out-tsc/src/aliaseditor/AliasEditor.js.map +1 -1
- package/out-tsc/src/button/Button.js +6 -2
- package/out-tsc/src/button/Button.js.map +1 -1
- package/out-tsc/src/chat/Chat.js +29 -7
- package/out-tsc/src/chat/Chat.js.map +1 -1
- package/out-tsc/src/compose/Compose.js +10 -5
- package/out-tsc/src/compose/Compose.js.map +1 -1
- package/out-tsc/src/contacts/ContactChat.js +240 -114
- package/out-tsc/src/contacts/ContactChat.js.map +1 -1
- package/out-tsc/src/contacts/ContactFieldEditor.js.map +1 -1
- package/out-tsc/src/contacts/events.js.map +1 -1
- package/out-tsc/src/contacts/helpers.js +5 -1
- package/out-tsc/src/contacts/helpers.js.map +1 -1
- package/out-tsc/src/contactsearch/ContactSearch.js +1 -1
- package/out-tsc/src/contactsearch/ContactSearch.js.map +1 -1
- package/out-tsc/src/dropdown/Dropdown.js +121 -108
- package/out-tsc/src/dropdown/Dropdown.js.map +1 -1
- package/out-tsc/src/interfaces.js +2 -0
- package/out-tsc/src/interfaces.js.map +1 -1
- package/out-tsc/src/list/ContentMenu.js +11 -8
- package/out-tsc/src/list/ContentMenu.js.map +1 -1
- package/out-tsc/src/list/RunList.js.map +1 -1
- package/out-tsc/src/list/TembaList.js +21 -14
- package/out-tsc/src/list/TembaList.js.map +1 -1
- package/out-tsc/src/list/TembaMenu.js +11 -12
- package/out-tsc/src/list/TembaMenu.js.map +1 -1
- package/out-tsc/src/list/TicketList.js +10 -0
- package/out-tsc/src/list/TicketList.js.map +1 -1
- package/out-tsc/src/omnibox/Omnibox.js +33 -90
- package/out-tsc/src/omnibox/Omnibox.js.map +1 -1
- package/out-tsc/src/options/Options.js +49 -47
- package/out-tsc/src/options/Options.js.map +1 -1
- package/out-tsc/src/select/PopupSelect.js +57 -0
- package/out-tsc/src/select/PopupSelect.js.map +1 -0
- package/out-tsc/src/select/Select.js +194 -144
- package/out-tsc/src/select/Select.js.map +1 -1
- package/out-tsc/src/select/UserSelect.js +67 -0
- package/out-tsc/src/select/UserSelect.js.map +1 -0
- package/out-tsc/src/store/Store.js +65 -14
- package/out-tsc/src/store/Store.js.map +1 -1
- package/out-tsc/src/tabpane/TabPane.js +72 -115
- package/out-tsc/src/tabpane/TabPane.js.map +1 -1
- package/out-tsc/src/textinput/TextInput.js +1 -0
- package/out-tsc/src/textinput/TextInput.js.map +1 -1
- package/out-tsc/src/user/TembaUser.js +24 -37
- package/out-tsc/src/user/TembaUser.js.map +1 -1
- package/out-tsc/src/utils/index.js +13 -6
- package/out-tsc/src/utils/index.js.map +1 -1
- package/out-tsc/temba-modules.js +4 -2
- package/out-tsc/temba-modules.js.map +1 -1
- package/out-tsc/test/temba-omnibox.test.js +43 -4
- package/out-tsc/test/temba-omnibox.test.js.map +1 -1
- package/out-tsc/test/temba-select.test.js +121 -65
- package/out-tsc/test/temba-select.test.js.map +1 -1
- package/out-tsc/test/utils.test.js +4 -0
- package/out-tsc/test/utils.test.js.map +1 -1
- package/package.json +1 -1
- package/screenshots/truth/compose/attachments-tab.png +0 -0
- package/screenshots/truth/compose/attachments-with-files-focused.png +0 -0
- package/screenshots/truth/compose/attachments-with-files.png +0 -0
- package/screenshots/truth/compose/intial-text.png +0 -0
- package/screenshots/truth/compose/no-counter.png +0 -0
- package/screenshots/truth/compose/wraps-text-and-spaces.png +0 -0
- package/screenshots/truth/compose/wraps-text-and-url.png +0 -0
- package/screenshots/truth/compose/wraps-text-no-spaces.png +0 -0
- package/screenshots/truth/contacts/chat-failure.png +0 -0
- package/screenshots/truth/contacts/chat-for-active-contact.png +0 -0
- package/screenshots/truth/contacts/chat-for-archived-contact.png +0 -0
- package/screenshots/truth/contacts/chat-for-blocked-contact.png +0 -0
- package/screenshots/truth/contacts/chat-for-stopped-contact.png +0 -0
- package/screenshots/truth/contacts/chat-sends-attachments-only.png +0 -0
- package/screenshots/truth/contacts/chat-sends-text-and-attachments.png +0 -0
- package/screenshots/truth/contacts/chat-sends-text-only.png +0 -0
- package/screenshots/truth/content-menu/item-no-buttons.png +0 -0
- package/screenshots/truth/content-menu/items-and-buttons.png +0 -0
- package/screenshots/truth/omnibox/selected.png +0 -0
- package/screenshots/truth/select/enabled-multi-selection.png +0 -0
- package/screenshots/truth/select/endpoint-initial-value-updated.png +0 -0
- package/screenshots/truth/select/endpoint-initial-value.png +0 -0
- package/screenshots/truth/select/expressions.png +0 -0
- package/screenshots/truth/select/functions.png +0 -0
- package/screenshots/truth/select/initial-value.png +0 -0
- package/screenshots/truth/select/multi-with-endpoint.png +0 -0
- package/screenshots/truth/select/multiple-initial-values.png +0 -0
- package/screenshots/truth/select/selected-multi-test.png +0 -0
- package/screenshots/truth/select/static-initial-value.png +0 -0
- package/screenshots/truth/select/static-initial-via-selected.png +0 -0
- package/screenshots/truth/select/value-initial.png +0 -0
- package/src/aliaseditor/AliasEditor.ts +1 -1
- package/src/button/Button.ts +6 -2
- package/src/chat/Chat.ts +28 -6
- package/src/compose/Compose.ts +11 -6
- package/src/contacts/ContactChat.ts +260 -118
- package/src/contacts/ContactFieldEditor.ts +1 -1
- package/src/contacts/events.ts +1 -0
- package/src/contacts/helpers.ts +8 -1
- package/src/contactsearch/ContactSearch.ts +3 -3
- package/src/dropdown/Dropdown.ts +142 -103
- package/src/interfaces.ts +4 -1
- package/src/list/ContentMenu.ts +11 -9
- package/src/list/RunList.ts +3 -1
- package/src/list/TembaList.ts +24 -14
- package/src/list/TembaMenu.ts +14 -15
- package/src/list/TicketList.ts +11 -0
- package/src/omnibox/Omnibox.ts +34 -95
- package/src/options/Options.ts +57 -60
- package/src/select/PopupSelect.ts +53 -0
- package/src/select/Select.ts +182 -112
- package/src/select/UserSelect.ts +71 -0
- package/src/store/Store.ts +70 -21
- package/src/tabpane/TabPane.ts +79 -113
- package/src/textinput/TextInput.ts +1 -0
- package/src/user/TembaUser.ts +30 -41
- package/src/utils/index.ts +12 -8
- package/temba-modules.ts +4 -2
- package/test/temba-omnibox.test.ts +56 -4
- package/test/temba-select.test.ts +170 -56
- package/test/utils.test.ts +5 -0
- package/test-assets/select/omnibox.json +55 -0
- package/web-test-runner.config.mjs +16 -4
- package/out-tsc/src/contacts/ContactTickets.js +0 -462
- package/out-tsc/src/contacts/ContactTickets.js.map +0 -1
- package/out-tsc/test/temba-contact-tickets.test.js +0 -36
- package/out-tsc/test/temba-contact-tickets.test.js.map +0 -1
- package/src/contacts/ContactTickets.ts +0 -490
- package/test/temba-contact-tickets.test.ts +0 -52
package/src/omnibox/Omnibox.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { TemplateResult, html,
|
|
1
|
+
import { TemplateResult, html, PropertyValues } from 'lit';
|
|
2
2
|
import { property } from 'lit/decorators.js';
|
|
3
3
|
import { styleMap } from 'lit-html/directives/style-map.js';
|
|
4
|
-
import {
|
|
5
|
-
import { Select } from '../select/Select';
|
|
4
|
+
import { Select, SelectOption } from '../select/Select';
|
|
6
5
|
import { Icon } from '../vectoricon';
|
|
7
6
|
|
|
8
7
|
enum OmniType {
|
|
@@ -10,7 +9,7 @@ enum OmniType {
|
|
|
10
9
|
Contact = 'contact'
|
|
11
10
|
}
|
|
12
11
|
|
|
13
|
-
export interface OmniOption {
|
|
12
|
+
export interface OmniOption extends SelectOption {
|
|
14
13
|
id: string;
|
|
15
14
|
name: string;
|
|
16
15
|
type: OmniType;
|
|
@@ -26,24 +25,9 @@ const postNameStyle = {
|
|
|
26
25
|
fontSize: '12px'
|
|
27
26
|
};
|
|
28
27
|
|
|
29
|
-
export class Omnibox extends
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
temba-select:focus {
|
|
33
|
-
outline: none;
|
|
34
|
-
box-shadow: none;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
:host {
|
|
38
|
-
}
|
|
39
|
-
`;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
@property()
|
|
43
|
-
endpoint: string;
|
|
44
|
-
|
|
45
|
-
@property()
|
|
46
|
-
name: string;
|
|
28
|
+
export class Omnibox extends Select<OmniOption> {
|
|
29
|
+
@property({ type: String })
|
|
30
|
+
valueKey = 'uuid';
|
|
47
31
|
|
|
48
32
|
@property({ type: Boolean })
|
|
49
33
|
groups = false;
|
|
@@ -51,38 +35,43 @@ export class Omnibox extends RapidElement {
|
|
|
51
35
|
@property({ type: Boolean })
|
|
52
36
|
contacts = false;
|
|
53
37
|
|
|
54
|
-
@property({ type:
|
|
55
|
-
value: OmniOption[] = [];
|
|
56
|
-
|
|
57
|
-
@property({ type: Array })
|
|
58
|
-
errors: string[];
|
|
59
|
-
|
|
60
|
-
@property()
|
|
38
|
+
@property({ type: String })
|
|
61
39
|
placeholder = 'Select recipients';
|
|
62
40
|
|
|
63
41
|
@property({ type: Boolean })
|
|
64
|
-
|
|
42
|
+
multi = true;
|
|
65
43
|
|
|
66
|
-
@property({ type:
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
@property({ type: Boolean, attribute: 'help_always' })
|
|
70
|
-
helpAlways: boolean;
|
|
44
|
+
@property({ type: Boolean })
|
|
45
|
+
searchable = true;
|
|
71
46
|
|
|
72
|
-
@property({ type: Boolean
|
|
73
|
-
|
|
47
|
+
@property({ type: Boolean })
|
|
48
|
+
searchOnFocus = true;
|
|
74
49
|
|
|
75
|
-
@property({ type: Boolean
|
|
76
|
-
|
|
50
|
+
@property({ type: Boolean })
|
|
51
|
+
queryParam = 'search';
|
|
52
|
+
|
|
53
|
+
public update(changes: PropertyValues): void {
|
|
54
|
+
super.update(changes);
|
|
55
|
+
|
|
56
|
+
if (
|
|
57
|
+
(changes.has('groups') || changes.has('contacts')) &&
|
|
58
|
+
(this.groups || this.contacts)
|
|
59
|
+
) {
|
|
60
|
+
let types = '&types=';
|
|
61
|
+
if (this.groups) {
|
|
62
|
+
types += 'g';
|
|
63
|
+
}
|
|
77
64
|
|
|
78
|
-
|
|
79
|
-
|
|
65
|
+
if (this.contacts) {
|
|
66
|
+
types += 'c';
|
|
67
|
+
}
|
|
80
68
|
|
|
81
|
-
|
|
82
|
-
|
|
69
|
+
this.endpoint = this.endpoint + types;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
83
72
|
|
|
84
73
|
/** An option in the drop down */
|
|
85
|
-
|
|
74
|
+
public renderOptionDefault(option: OmniOption): TemplateResult {
|
|
86
75
|
return html`
|
|
87
76
|
<div style="display:flex;">
|
|
88
77
|
<div style="margin-right: 8px">${this.getIcon(option)}</div>
|
|
@@ -115,7 +104,7 @@ export class Omnibox extends RapidElement {
|
|
|
115
104
|
}
|
|
116
105
|
|
|
117
106
|
/** Selection in the multi-select select box */
|
|
118
|
-
|
|
107
|
+
public renderSelectedItemDefault(option: OmniOption): TemplateResult {
|
|
119
108
|
return html`
|
|
120
109
|
<div
|
|
121
110
|
style="flex:1 1 auto; display: flex; align-items: stretch; color: var(--color-text-dark); font-size: 12px;"
|
|
@@ -147,54 +136,4 @@ export class Omnibox extends RapidElement {
|
|
|
147
136
|
return html`<temba-icon name="${Icon.contact}"></temba-icon>`;
|
|
148
137
|
}
|
|
149
138
|
}
|
|
150
|
-
|
|
151
|
-
private getEndpoint() {
|
|
152
|
-
const endpoint = this.endpoint;
|
|
153
|
-
let types = '&types=';
|
|
154
|
-
if (this.groups) {
|
|
155
|
-
types += 'g';
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
if (this.contacts) {
|
|
159
|
-
types += 'c';
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
return endpoint + types;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
public getValues(): any[] {
|
|
166
|
-
const select = this.shadowRoot.querySelector('temba-select') as Select;
|
|
167
|
-
return select.values;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
public isMatch() {
|
|
171
|
-
return true;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
public render(): TemplateResult {
|
|
175
|
-
return html`
|
|
176
|
-
<temba-select
|
|
177
|
-
name=${this.name}
|
|
178
|
-
endpoint=${this.getEndpoint()}
|
|
179
|
-
placeholder=${this.placeholder}
|
|
180
|
-
queryParam="search"
|
|
181
|
-
.label=${this.label}
|
|
182
|
-
.helpText=${this.helpText}
|
|
183
|
-
.widgetOnly=${this.widgetOnly}
|
|
184
|
-
?disabled=${this.disabled}
|
|
185
|
-
.errors=${this.errors}
|
|
186
|
-
.values=${this.value}
|
|
187
|
-
.renderOption=${this.renderOption.bind(this)}
|
|
188
|
-
.renderSelectedItem=${this.renderSelection.bind(this)}
|
|
189
|
-
.inputRoot=${this}
|
|
190
|
-
.isMatch=${this.isMatch}
|
|
191
|
-
.infoText=${this.infoText}
|
|
192
|
-
searchable
|
|
193
|
-
searchOnFocus
|
|
194
|
-
multi
|
|
195
|
-
><div slot="right">
|
|
196
|
-
<slot name="right"></slot></div
|
|
197
|
-
></temba-select>
|
|
198
|
-
`;
|
|
199
|
-
}
|
|
200
139
|
}
|
package/src/options/Options.ts
CHANGED
|
@@ -3,16 +3,15 @@ import { property } from 'lit/decorators.js';
|
|
|
3
3
|
import { CustomEventType } from '../interfaces';
|
|
4
4
|
import { RapidElement, EventHandler } from '../RapidElement';
|
|
5
5
|
import { styleMap } from 'lit-html/directives/style-map.js';
|
|
6
|
-
import {
|
|
7
|
-
getClasses,
|
|
8
|
-
getScrollParent,
|
|
9
|
-
isElementVisible,
|
|
10
|
-
throttle
|
|
11
|
-
} from '../utils';
|
|
6
|
+
import { getClasses, getScrollParent, throttle } from '../utils';
|
|
12
7
|
|
|
13
8
|
export class Options extends RapidElement {
|
|
14
9
|
static get styles() {
|
|
15
10
|
return css`
|
|
11
|
+
:host {
|
|
12
|
+
--transition-speed: 0;
|
|
13
|
+
}
|
|
14
|
+
|
|
16
15
|
.options-container {
|
|
17
16
|
background: var(--color-options-bg);
|
|
18
17
|
user-select: none;
|
|
@@ -21,7 +20,7 @@ export class Options extends RapidElement {
|
|
|
21
20
|
margin-top: var(--options-margin-top);
|
|
22
21
|
display: flex;
|
|
23
22
|
flex-direction: column;
|
|
24
|
-
transform: scaleY(0.5) translateY(-5em);
|
|
23
|
+
// transform: scaleY(0.5) translateY(-5em);
|
|
25
24
|
transition: transform var(--transition-speed)
|
|
26
25
|
cubic-bezier(0.71, 0.18, 0.61, 1.33),
|
|
27
26
|
opacity var(--transition-speed) cubic-bezier(0.71, 0.18, 0.61, 1.33);
|
|
@@ -93,12 +92,12 @@ export class Options extends RapidElement {
|
|
|
93
92
|
.options {
|
|
94
93
|
border-radius: var(--curvature-widget);
|
|
95
94
|
overflow-y: auto;
|
|
96
|
-
max-height:
|
|
95
|
+
max-height: 200px;
|
|
97
96
|
border: none;
|
|
98
97
|
}
|
|
99
98
|
|
|
100
99
|
.show {
|
|
101
|
-
transform: scaleY(1) translateY(0);
|
|
100
|
+
// transform: scaleY(1) translateY(0);
|
|
102
101
|
border: 1px solid var(--color-widget-border);
|
|
103
102
|
opacity: 1;
|
|
104
103
|
z-index: 1;
|
|
@@ -281,14 +280,14 @@ export class Options extends RapidElement {
|
|
|
281
280
|
|
|
282
281
|
resolvedRenderOption: { (option: any, selected: boolean): TemplateResult };
|
|
283
282
|
|
|
284
|
-
public firstUpdated() {
|
|
283
|
+
public firstUpdated(changed: Map<string, any>) {
|
|
284
|
+
super.firstUpdated(changed);
|
|
285
285
|
if (!this.block) {
|
|
286
286
|
this.scrollParent = getScrollParent(this);
|
|
287
287
|
this.calculatePosition = this.calculatePosition.bind(this);
|
|
288
288
|
if (this.scrollParent) {
|
|
289
289
|
this.scrollParent.addEventListener('scroll', this.calculatePosition);
|
|
290
290
|
}
|
|
291
|
-
this.calculatePosition();
|
|
292
291
|
}
|
|
293
292
|
|
|
294
293
|
this.resolvedRenderOption = (
|
|
@@ -302,9 +301,14 @@ export class Options extends RapidElement {
|
|
|
302
301
|
this.scrollParent.removeEventListener('scroll', this.calculatePosition);
|
|
303
302
|
}
|
|
304
303
|
}
|
|
304
|
+
|
|
305
|
+
if (this.resizeObserver) {
|
|
306
|
+
this.resizeObserver.disconnect();
|
|
307
|
+
}
|
|
305
308
|
}
|
|
306
309
|
|
|
307
|
-
private isFocused() {
|
|
310
|
+
private isFocused(): boolean {
|
|
311
|
+
// TODO: this really doesn't seem right
|
|
308
312
|
const focused =
|
|
309
313
|
this.closestElement(document.activeElement.tagName) ===
|
|
310
314
|
document.activeElement;
|
|
@@ -312,9 +316,29 @@ export class Options extends RapidElement {
|
|
|
312
316
|
return focused;
|
|
313
317
|
}
|
|
314
318
|
|
|
319
|
+
private resizeObserver: ResizeObserver;
|
|
320
|
+
|
|
315
321
|
public updated(changed: Map<string, any>) {
|
|
316
322
|
super.updated(changed);
|
|
317
323
|
|
|
324
|
+
if (changed.has('anchorTo') && this.anchorTo) {
|
|
325
|
+
const optionsContainer =
|
|
326
|
+
this.shadowRoot.querySelector('.options-container');
|
|
327
|
+
|
|
328
|
+
if (!this.resizeObserver) {
|
|
329
|
+
this.resizeObserver = new ResizeObserver((entries) => {
|
|
330
|
+
window.requestAnimationFrame((): void | undefined => {
|
|
331
|
+
if (!Array.isArray(entries) || !entries.length) {
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
this.calculatePosition();
|
|
335
|
+
this.adjustWidth();
|
|
336
|
+
});
|
|
337
|
+
});
|
|
338
|
+
this.resizeObserver.observe(optionsContainer);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
318
342
|
// if our cursor changed, lets make sure our scrollbox is showing it
|
|
319
343
|
if (!this.internalFocusDisabled && changed.has('cursorIndex')) {
|
|
320
344
|
this.fireCustomEvent(CustomEventType.CursorChanged, {
|
|
@@ -327,11 +351,12 @@ export class Options extends RapidElement {
|
|
|
327
351
|
this.tempOptions = changed.get('options');
|
|
328
352
|
window.setTimeout(() => {
|
|
329
353
|
this.tempOptions = [];
|
|
330
|
-
},
|
|
354
|
+
}, 0);
|
|
331
355
|
}
|
|
332
356
|
}
|
|
333
357
|
|
|
334
358
|
if (changed.has('options')) {
|
|
359
|
+
this.adjustWidth();
|
|
335
360
|
this.calculatePosition();
|
|
336
361
|
|
|
337
362
|
// allow scrolls to trigger again
|
|
@@ -370,12 +395,6 @@ export class Options extends RapidElement {
|
|
|
370
395
|
}
|
|
371
396
|
}
|
|
372
397
|
}
|
|
373
|
-
|
|
374
|
-
if (changed.has('visible')) {
|
|
375
|
-
window.setTimeout(() => {
|
|
376
|
-
this.calculatePosition();
|
|
377
|
-
}, 100);
|
|
378
|
-
}
|
|
379
398
|
}
|
|
380
399
|
|
|
381
400
|
private renderOptionDefault(option: any, selected: boolean): TemplateResult {
|
|
@@ -528,6 +547,16 @@ export class Options extends RapidElement {
|
|
|
528
547
|
}
|
|
529
548
|
}
|
|
530
549
|
|
|
550
|
+
private adjustWidth() {
|
|
551
|
+
if (this.anchorTo) {
|
|
552
|
+
const anchorBounds = this.anchorTo.getBoundingClientRect();
|
|
553
|
+
this.width =
|
|
554
|
+
this.staticWidth > 0
|
|
555
|
+
? this.staticWidth
|
|
556
|
+
: anchorBounds.width - 2 - this.marginHorizontal * 2;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
531
560
|
private calculatePosition() {
|
|
532
561
|
if (this.visible && !this.block) {
|
|
533
562
|
const optionsBounds = this.shadowRoot
|
|
@@ -535,34 +564,16 @@ export class Options extends RapidElement {
|
|
|
535
564
|
.getBoundingClientRect();
|
|
536
565
|
|
|
537
566
|
if (this.anchorTo) {
|
|
567
|
+
this.top = 0;
|
|
538
568
|
const anchorBounds = this.anchorTo.getBoundingClientRect();
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
if (this.anchorTo && this.scrollParent) {
|
|
542
|
-
if (!isElementVisible(this.anchorTo, this.scrollParent)) {
|
|
543
|
-
// this.fireCustomEvent(CustomEventType.Canceled);
|
|
544
|
-
}
|
|
569
|
+
if (anchorBounds.bottom + optionsBounds.height > window.innerHeight) {
|
|
570
|
+
this.top = -(optionsBounds.height + anchorBounds.height + 20);
|
|
545
571
|
}
|
|
546
|
-
|
|
547
|
-
if (
|
|
548
|
-
topTop > 0 &&
|
|
549
|
-
anchorBounds.bottom + optionsBounds.height > window.innerHeight
|
|
550
|
-
) {
|
|
551
|
-
this.top = topTop; // + window.pageYOffset;
|
|
552
|
-
this.poppedTop = true;
|
|
553
|
-
} else {
|
|
554
|
-
this.top = anchorBounds.bottom; // + window.pageYOffset;
|
|
555
|
-
this.poppedTop = false;
|
|
556
|
-
}
|
|
557
|
-
|
|
558
572
|
this.left = anchorBounds.left;
|
|
559
|
-
this.width =
|
|
560
|
-
this.staticWidth > 0
|
|
561
|
-
? this.staticWidth
|
|
562
|
-
: anchorBounds.width - 2 - this.marginHorizontal * 2;
|
|
563
573
|
|
|
564
|
-
|
|
565
|
-
|
|
574
|
+
// adjust for parent scrolling
|
|
575
|
+
if (this.scrollParent) {
|
|
576
|
+
this.top += -this.scrollParent.scrollTop;
|
|
566
577
|
}
|
|
567
578
|
}
|
|
568
579
|
}
|
|
@@ -594,16 +605,7 @@ export class Options extends RapidElement {
|
|
|
594
605
|
}
|
|
595
606
|
}
|
|
596
607
|
|
|
597
|
-
// we need to swallow mouse down so we don't grab focus
|
|
598
|
-
private handleMouseDown(evt: MouseEvent) {
|
|
599
|
-
evt.preventDefault();
|
|
600
|
-
evt.stopPropagation();
|
|
601
|
-
}
|
|
602
|
-
|
|
603
608
|
private handleOptionClick(evt: MouseEvent) {
|
|
604
|
-
evt.preventDefault();
|
|
605
|
-
evt.stopPropagation();
|
|
606
|
-
|
|
607
609
|
const index = (evt.currentTarget as HTMLElement).getAttribute(
|
|
608
610
|
'data-option-index'
|
|
609
611
|
);
|
|
@@ -631,7 +633,7 @@ export class Options extends RapidElement {
|
|
|
631
633
|
};
|
|
632
634
|
|
|
633
635
|
if (this.top) {
|
|
634
|
-
containerStyle[
|
|
636
|
+
containerStyle[`transform`] = `translateY(${this.top}px)`;
|
|
635
637
|
}
|
|
636
638
|
|
|
637
639
|
if (this.left) {
|
|
@@ -668,18 +670,13 @@ export class Options extends RapidElement {
|
|
|
668
670
|
|
|
669
671
|
return html`
|
|
670
672
|
<div class=${classes} style=${styleMap(containerStyle)}>
|
|
671
|
-
<div
|
|
672
|
-
class="options-scroll"
|
|
673
|
-
@scroll=${this.handleInnerScroll}
|
|
674
|
-
@mousedown=${this.handleMouseDown}
|
|
675
|
-
>
|
|
673
|
+
<div class="options-scroll" @scroll=${this.handleInnerScroll}>
|
|
676
674
|
<div class="${classesInner}" style=${styleMap(optionsStyle)}>
|
|
677
675
|
${options.map((option, index) => {
|
|
678
676
|
return html`<div
|
|
679
677
|
data-option-index="${index}"
|
|
680
678
|
@mousemove=${this.handleMouseMove}
|
|
681
|
-
@
|
|
682
|
-
@mousedown=${this.handleMouseDown}
|
|
679
|
+
@mousedown=${this.handleOptionClick}
|
|
683
680
|
class="option ${index === this.cursorIndex &&
|
|
684
681
|
!this.internalFocusDisabled
|
|
685
682
|
? 'focused'
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { css, html } from 'lit';
|
|
2
|
+
import { RapidElement } from '../RapidElement';
|
|
3
|
+
import { property } from 'lit/decorators.js';
|
|
4
|
+
|
|
5
|
+
export class PopupSelect extends RapidElement {
|
|
6
|
+
public static styles = css`
|
|
7
|
+
:host {
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.dropdown {
|
|
11
|
+
background: #fff;
|
|
12
|
+
border-radius: 0.5em;
|
|
13
|
+
padding: 0.15em;
|
|
14
|
+
border-radius: var(--curvature);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
temba-select {
|
|
18
|
+
width: 250px;
|
|
19
|
+
display: block;
|
|
20
|
+
--color-widget-border: transparent;
|
|
21
|
+
--widget-box-shadow: none;
|
|
22
|
+
}
|
|
23
|
+
`;
|
|
24
|
+
|
|
25
|
+
@property({ type: String })
|
|
26
|
+
placeholder: string = '';
|
|
27
|
+
|
|
28
|
+
@property({ type: String })
|
|
29
|
+
endpoint: string = '';
|
|
30
|
+
|
|
31
|
+
private handleChange() {
|
|
32
|
+
this.blur();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
public render() {
|
|
36
|
+
return html`
|
|
37
|
+
<div>
|
|
38
|
+
<temba-dropdown>
|
|
39
|
+
<div slot="toggle"><slot name="toggle"></slot></div>
|
|
40
|
+
<div class="dropdown" slot="dropdown">
|
|
41
|
+
<temba-select
|
|
42
|
+
placeholder=${this.placeholder}
|
|
43
|
+
endpoint=${this.endpoint}
|
|
44
|
+
clearable
|
|
45
|
+
searchable
|
|
46
|
+
@change=${this.handleChange}
|
|
47
|
+
></temba-select>
|
|
48
|
+
</div>
|
|
49
|
+
</temba-dropdown>
|
|
50
|
+
</div>
|
|
51
|
+
`;
|
|
52
|
+
}
|
|
53
|
+
}
|